我正在做一个有文章的网站,我需要文章有“友好”的url,基于标题。

例如,如果我的文章标题是“文章测试”,我希望URL是http://www.example.com/articles/article_test。

但是,文章标题(与任何字符串一样)可以包含多个特殊字符,这些字符不可能直接放在我的URL中。比如说,我知道?或#需要被替换,但我不知道所有其他。

url中允许使用哪些字符?什么东西是安全的?


URI的格式在RFC 3986中定义。详见3.3节。


我认为你正在寻找类似“URL编码”的东西——对URL进行编码,以便在网络上使用它是“安全的”:

这里有一个参考。如果你不想要任何特殊字符,只需删除任何需要URL编码的字符:

HTML URL编码参考


您最好只保留一些字符(白名单),而不是删除某些字符(黑名单)。

从技术上讲,你可以允许任何字符,只要你正确地编码它。但是,为了回答这个问题的精神,你应该只允许这些字符:

小写字母(将大写字母转换为小写字母) 数字,0到9 破折号或下划线_ 波浪号~

其他的一切都有潜在的特殊意义。例如,您可能认为可以使用+,但可以用空格替换。&也是危险的,特别是在使用一些重写规则时。

与其他注释一样,请查看标准和规范以获得完整的详细信息。


您需要注意两组字符:保留字符和不安全字符。

保留字符为:

&(“&”) 美元(美元) 加号(“+”) 逗号(,) 正斜杠("/") 冒号(“:”) 分号(“;”) = (" = ") 问号(“?”) “At”符号(“@”) 英镑(“#”)。

一般认为不安全的字符有:

空格(" ") 小于大于("<>") 左右括号("[]") 前后大括号("{}") 管(“|”) 反斜杠(\) 插入符号(“^”) 百分比(%)

我可能忘记了一个或多个,这导致我重复卡尔V的答案。从长远来看,您最好使用允许字符的“白名单”,然后对字符串进行编码,而不是试图与服务器和系统不允许的字符保持一致。


引用RFC 3986第2.3节:

URI中允许的但没有保留的字符 目的,都叫无保留。这包括大写和小写 字母、十进制数字、连字符、句号、下划线和波浪号。 字母数字"-" / "。"/ "_" / "~"

注意,RFC 3986比旧的RFC 2396列出了更少的保留标点符号。


从你所描述的上下文来看,我怀疑你实际上想要做的是一种叫做“SEO slug”的东西。最常见的做法是:

转换为小写 将除a-z和0-9之外的整个字符序列转换为一个连字符(-)(不是下划线) 从URL中删除“停止词”,即“a”、“an”和“the”等无意义的可索引词;谷歌用于广泛列表的“停止词”

举个例子,一篇名为“漫画中使用!@%$*来表示脏话”的文章会出现“用法-表示-脏话-漫画”。


从SEO的角度来看,连字符比下划线更受欢迎。转换为小写,删除所有撇号,然后用一个连字符替换所有非字母数字字符字符串。修剪多余的连字符从开始和结束。


unreserved = ALPHA / DIGIT / "-" / "."/ "_" / "~"


我也遇到过类似的问题。我想拥有漂亮的url,并得出结论,我必须只允许字母,数字,-和_在url中。

这很好,但后来我写了一些漂亮的正则表达式,我意识到它识别所有UTF-8字符不是。net中的字母,这是搞砸了。对于. net正则表达式引擎来说,这似乎是一个众所周知的问题。所以我得到了这个解决方案:

private static string GetTitleForUrlDisplay(string title)
{
    if (!string.IsNullOrEmpty(title))
    {
        return Regex.Replace(Regex.Replace(title, @"[^A-Za-z0-9_-]", new MatchEvaluator(CharacterTester)).Replace(' ', '-').TrimStart('-').TrimEnd('-'), "[-]+", "-").ToLower();
    }
    return string.Empty;
}


/// <summary>
/// All characters that do not match the patter, will get to this method, i.e. useful for Unicode characters, because
/// .NET implementation of regex do not handle Unicode characters. So we use char.IsLetterOrDigit() which works nicely and we
/// return what we approve and return - for everything else.
/// </summary>
/// <param name="m"></param>
/// <returns></returns>
private static string CharacterTester(Match m)
{
    string x = m.ToString();
    if (x.Length > 0 && char.IsLetterOrDigit(x[0]))
    {
        return x.ToLower();
    }
    else
    {
        return "-";
    }
}

看看RFC3986 -统一资源标识符(URI):通用语法,你的问题围绕着URI的路径组件。

foo: / / example.com: 8042 / / / ? name =雪貂#鼻子

     \_/   \______________/\_________/ \_________/ \__/
      |           |            |            |        |
   scheme     authority       path        query   fragment
      |   _____________________|__
     / \ /                        \
     urn:example:animal:ferret:nose

引用3.3节,URI段的有效字符类型为pchar:

Pchar = unreserved / pct-encoded / sub-delims / ":" / "@"

具体分为:

Alpha / digit / "-" / "."/ "_" / "~" pct-encoded “啊!”/ "$" / "&" / "'" / "(" / ")"/ "*" / "+" / " " / ";"/“=” ":" / "@"

或者换句话说:您可以使用ASCII表中的任何(非控制-)字符,除了/,?,#,[和]。

这一理解得到了RFC1738 -统一资源定位符(URL)的支持。


我发现当我通过Ajax/PHP返回一个值到一个URL,然后由页面再次读取时,将我的URL编码为一个安全的URL非常有用。

PHP输出与URL编码器的特殊字符&:

// PHP returning the success information of an Ajax request
echo "".str_replace('&', '%26', $_POST['name']) . " category was changed";

// JavaScript sending the value to the URL
window.location.href = 'time.php?return=updated&val=' + msg;

// JavaScript/PHP executing the function printing the value of the URL,
// now with the text normally lost in space because of the reserved & character.

setTimeout("infoApp('updated','<?php echo $_GET['val'];?>');", 360);

3-50个字符之间。可以包含小写字母、数字和特殊字符——点(.)、破折号(-)、下划线(_)和@。


总是安全的

在理论上和规范上,除了域名之外,这些基本在任何地方都是安全的。对未列出的内容进行百分比编码,就可以开始了。

    A-Z a-z 0-9 - . _ ~ ( ) ' ! * : @ , ;

有时安全

只有在特定URL组件中使用才安全;小心使用。

    Paths:     + & =
    Queries:   ? /
    Fragments: ? / # + & =
    

不安全的

根据URI规范(RFC 3986),所有其他字符必须用百分比编码。这包括:

    <space> <control-characters> <extended-ascii> <unicode>
    % < > [ ] { } | \ ^
    

如果最大兼容性是一个问题,限制字符集为a-z a-z 0-9 - _。(仅对文件名扩展名使用句点)。

牢记语境

即使根据规范有效,URL仍然可能是“不安全的”,这取决于上下文。例如包含无效文件名字符的file:/// URL,或者不用作分隔符时包含“?”、“=”和“&”的查询组件。这些情况的正确处理通常取决于您的脚本,并且可以解决,但这是需要记住的事情。