有人知道可以在GET中使用而不经过编码的完整字符列表吗?目前我使用A-Z - A-Z和0-9…但我想知道完整的名单。
我也感兴趣的是,是否会发布关于即将添加中文、阿拉伯语url的规范(显然这将对我的问题产生很大影响)。
URI中允许的字符要么是保留的,要么是不保留的(或者是百分比字符作为百分比编码的一部分)。
http://en.wikipedia.org/wiki/Percent-encoding#Types_of_URI_characters
说这些是RFC 3986 无限制的字符(第2.3节)以及保留字符(第2.2节),如果他们需要保留他们的特殊含义。还有一个百分比字符作为百分比编码的一部分。
从在这里
因此,只有字母数字,特殊字符$-_.+!*'(), 以及用于their的保留字符 保留的目的可以在URL中使用未编码的方式
$-_.+!*'(),
EDIT:正如@Jukka K. Korpela正确指出的那样,RFC 1738由RFC 3986更新。 这已经扩展和澄清了对主机有效的字符,不幸的是,它不容易复制和粘贴,但我会尽我最大的努力
按首先匹配的顺序排列:
host = IP-literal / IPv4address / reg-name IP-literal = "[" ( IPv6address / IPvFuture ) "]" IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) IPv6address = 6( h16 ":" ) ls32 / "::" 5( h16 ":" ) ls32 / [ h16 ] "::" 4( h16 ":" ) ls32 / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 / [ *4( h16 ":" ) h16 ] "::" ls32 / [ *5( h16 ":" ) h16 ] "::" h16 / [ *6( h16 ":" ) h16 ] "::" ls32 = ( h16 ":" h16 ) / IPv4address ; least-significant 32 bits of address h16 = 1*4HEXDIG ; 16 bits of address represented in hexadecimal IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet dec-octet = DIGIT ; 0-9 / %x31-39 DIGIT ; 10-99 / "1" 2DIGIT ; 100-199 / "2" %x30-34 DIGIT ; 200-249 / "25" %x30-35 ; 250-255 reg-name = *( unreserved / pct-encoded / sub-delims ) unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" <---This seems like a practical shortcut, most closely resembling original answer reserved = gen-delims / sub-delims gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" pct-encoded = "%" HEXDIG HEXDIG
RFC 1738规范的原始答案:
因此,只有字母数字,特殊字符"$-_.+!*'(),"和 可以使用用于保留目的的保留字符
^自1998年起过时。
它们在RFC3986中列出。请参阅为URI收集ABNF来查看允许在哪里执行什么操作,以及正则表达式用于解析/验证。
即将到来的改变是针对中文,阿拉伯语域名,而不是uri。国际化的uri称为iri,在RFC 3987中定义。尽管如此,我还是建议不要自己这么做,而是依赖于现有的、经过测试的库,因为有很多URI编码/解码的选择,以及规范上认为安全的,以及实际使用(浏览器)上认为安全的。
66个无保留字符的完整列表在RFC3986中,这里:https://www.rfc-editor.org/rfc/rfc3986#section-2.3
这是以下正则表达式集中的任何字符:
[A-Za-z0-9_.\-~]
RFC3986定义了两组你可以在URI中使用的字符:
:/?#[]@!$&'()*+,;=
保留= gen-delims / sub-delims Gen-delims = ":" /" /" /" ?"/ "#" / "[" / "]" / "@" Sub-delims = "!"/ "$" / "&"/ "'" / "(" / ")"/ "*" / "+" / " " / ";"/“=” 保留字符的目的是提供一组分隔字符,以便与URI中的其他数据区分开来。在保留字符替换为其相应的百分比编码字节方面存在差异的uri是不相等的。 李< /引用> < / > < p > 无限制的字符: A-Za-z0-9-_.~ unreserved = ALPHA / DIGIT / "-" / "."/ "_" / "~" URI中允许但没有保留目的的字符称为无保留字符。 李< /引用> < / >
保留= gen-delims / sub-delims
Gen-delims = ":" /" /" /" ?"/ "#" / "[" / "]" / "@"
Sub-delims = "!"/ "$" / "&"/ "'" / "(" / ")"/ "*" / "+" / " " / ";"/“=”
保留字符的目的是提供一组分隔字符,以便与URI中的其他数据区分开来。在保留字符替换为其相应的百分比编码字节方面存在差异的uri是不相等的。
A-Za-z0-9-_.~
unreserved = ALPHA / DIGIT / "-" / "."/ "_" / "~" URI中允许但没有保留目的的字符称为无保留字符。 李< /引用> < / >
unreserved = ALPHA / DIGIT / "-" / "."/ "_" / "~"
URI中允许但没有保留目的的字符称为无保留字符。
我测试它通过请求我的网站(apache)与所有可用的字符在我的德语键盘作为URL参数:
http://example.com/?^1234567890ß´qwertzuiopü+asdfghjklöä#<yxcvbnm,.-°!"§$%&/()=? `QWERTZUIOPÜ*ASDFGHJKLÖÄ\'>YXCVBNM;:_²³{[]}\|µ@€~
这些没有被编码:
^0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.-!/()=?`*;:_{}[]\|~
没有在urlencode()之后编码:
urlencode()
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_
没有在rawurlencode()之后编码:
rawurlencode()
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~
注意:在PHP 5.3.0之前,rawurlencode()编码了~,因为RFC 1738。但这被RFC 3986所取代,所以现在可以安全使用了。但我不明白为什么例如{}是通过rawurlencode()编码的,因为它们在RFC 3986中没有提到。
~
{}
我做的另一个测试是关于邮件文本中的自动链接。我测试了Mozilla Thunderbird, aol.com, outlook.com, gmail.com, gmx.de和yahoo.de,他们完全链接包含这些字符的url:
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~+#,%&=*;:@
当然?也被链接了,但前提是它只被使用了一次。
?
有些人现在建议只使用rawurlencode()字符,但你是否听说过有人在打开这些网站时遇到问题?
正因为如此,这些字符应该可以在没有编码的情况下使用。当然你不应该使用&;,因为像&这样的编码序列。同样的原因也适用于%,因为它通常用于编码字符。和=,因为它为参数名赋值。
&;
&
%
=
最后,我想说的是,可以使用这些未编码的:
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_~!+,*:@
但如果你希望随机生成url,你不应该使用像.!这样的标点符号,因为一些邮件应用程序不会自动链接它们:
.!
http://example.com/?foo=bar !& lt;最后一个字符未链接
如果你想给用户一种特殊的体验,你可以使用pushState为浏览器的url带来广泛的字符:
pushState
var u="";var tt=168; for(var i=0; i< 250;i++){ var x = i+250*tt; console.log(x); var c = String.fromCharCode(x); u+=c; } history.pushState({},"",250*tt+u);
这个答案讨论了字符可以包含在URL片段部分中而不进行转义。我单独发布了一个答案,因为这部分与这里的其他优秀答案略有不同(并且可以结合使用)。
片段部分不会被发送到服务器,在本例中,它是#后面的字符:
#
https://example.com/#STUFF-HERE
RFC 3986中的相关规范是:
fragment = *( pchar / "/" / "?" ) pchar = unreserved / pct-encoded / sub-delims / ":" / "@" unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
这也引用了RFC 2234中的规则
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z DIGIT = %x30-39 ; 0-9
因此,不包括转义(pct-encoded)的完整列表为:
pct-encoded
__abc0 __abc1 __abc2 __abc3 __abc4 __abc5 __abc6 __abc7 __abc8 __abc9 __abc10 __abc11 __abc12 __abc13 __abc14 __abc15 __abc16 __abc17 __abc18 __abc19 __abc20 __abc21
为了方便起见,这里有一个匹配有效的、未转义的片段的PCRE表达式:
/^[A-Za-z0-9\-._~!$&'()*+,;=:@\/?]*$/
算起来,有:
26 + 26 + 10 + 19 = 81个码位
您可以使用基数81来有效地编码这里的数据。