哪些字符使网址无效?

时间:2009-10-10 13:10:52

标签: validation url rfc3986

哪些字符使网址无效?

这些有效的网址吗?

  • example.com/file[/].html
  • http://example.com/file[/].html

10 个答案:

答案 0 :(得分:549)

一般来说,RFC 3986定义的URI(请参阅Section 2: Characters)可能包含以下任何字符:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=

请注意,此列表未说明URI中可能出现这些字符的位置。

任何其他字符都需要使用百分比编码进行编码(% hh )。 URI的每个部分都对进行百分比编码的单词需要表示的字符有进一步的限制。

答案 1 :(得分:168)

要添加一些说明并直接解决上述问题,有几类字符会导致URL和URI出现问题。

有些字符是不允许的,不应出现在URL / URI,保留字符(如下所述)中,以及在某些情况下可能导致问题的其他字符,但标记为“不明智”或“不安全”。在RFC-1738(URL)和RFC-2396(URI)中明确说明了字符受限制的原因。请注意,较新的RFC-3986(对RFC-1738的更新)定义了在给定上下文中允许使用哪些字符的构造,但较旧的规范提供了对以下规则不允许哪些字符的更简单和更一般的描述。 / p>

URI语法中不允许使用排除的US-ASCII字符:

   control     = <US-ASCII coded characters 00-1F and 7F hexadecimal>
   space       = <US-ASCII coded character 20 hexadecimal>
   delims      = "<" | ">" | "#" | "%" | <">

排除字符“#”,因为它用于从片段标识符分隔URI。百分比字符“%”被排除,因为它用于转义字符的编码。换句话说,“#”和“%”是必须在特定上下文中使用的保留字符。

允许列出不明智的字符,但可能会导致问题:

   unwise      = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"

查询组件中reserved的字符和/或URI / URL中的特殊含义:

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","

上面的“保留”语法类是指URI中允许的那些字符,但在通用URI语法的特定组件中可能不允许这些字符。 “保留”集中的字符不会在所有上下文中保留。例如,主机名可以包含可选的用户名,因此它可以是ftp://user@hostname/,其中“@”字符具有特殊含义。

以下是包含无效和不明智字符的网址示例(例如'$','[',']'),并且应正确编码:

http://mw1.google.com/mw-earth-vectordb/kml-samples/gp/seattle/gigapxl/$[level]/r$[y]_c$[x].jpg

URI / URL的一些字符限制是依赖于编程语言的。例如,'|' (0x7C)字符虽然在URI规范中仅标记为“不明智”,但会在Java java.net.URI 构造函数中抛出 URISyntaxException ,因此像{{1}这样的URL如果将Java与URI对象实例一起使用,则不允许编码,而必须编码为http://api.google.com/q?exp=a|b

答案 2 :(得分:67)

这里的大多数现有答案都是不切实际的,因为它们完全忽略了地址的实际使用情况,如:

首先,对术语的偏离? 这些地址是什么?它们是有效的网址吗?

历史上,答案是“不”。根据{{​​3}},从2005年开始,此类地址不是URI(因此不是URL,因为URL RFC 3986)。根据2005 IETF标准的术语,我们应该正确地称它们为are a type of URIs中定义的IRI(国际化资源标识符),它们在技术上不是URI,但可以通过百分比编码所有非ASCII字符转换为URI在IRI。

根据现代规范,答案是肯定的。 RFC 3987只是将以前称为“URI”或“IRI”的所有内容分类为“URL”。这使得所使用的术语与未阅读规范的普通人使用单词“URL”的方式保持一致,后者是规范WHATWG Living Standard之一。

WHATWG生活标准允许哪些字符?

根据“URL”这个更新的含义,允许使用哪些字符?在URL的许多部分,例如查询字符串和路径,我们可以使用任意goals,这是

  

"URL units"URL code points

什么是“网址代码点”?

  

网址代码是ASCII字母数字,U + 0021(!),U + 0024($),U + 0026(&amp;),U + 0027('),U + 0028 LEFT PARENTHESIS,U + 0029右父母,U + 002A(*),U + 002B(+),U + 002C(,),U + 002D( - ),U + 002E(。),U + 002F(/) ,U + 003A(:),U + 003B(;),U + 003D(=),U + 003F(?),U + 0040(@),U + 005F(_),U + 007E(〜),和代码点在U + 00A0到U + 10FFFD范围内,包括代理和非特征。

(请注意,“网址代码点”列表不包含%,但如果它们是百分比编码的一部分,那么“网址代码单元”中允许使用%序列。)

我唯一可以看到规范允许在此集合中使用的字符的地方位于percent-encoded bytes,其中IPv6地址包含在[中和]个字符。 URL中的其他任何位置都允许使用URL单元,或者使用一些限制性更强的字符集。

旧RFC下允许哪些字符?

为了历史,并且因为在这里答案的其他地方没有完全探讨,所以我们可以根据较旧的规格进行检查。

首先,我们有两种类型的RFC 3986 host

  • :/?#[]@ ,它们是RFC 3986中定义的URI的通用语法的一部分
  • !$&'()*+,;= ,它们不是RFC的通用语法的一部分,但保留用作特定URI方案的语法组件。例如,分号和逗号用作reserved characters语法的一部分,&=用作查询字符串中普遍存在的?foo=bar&qux=baz格式的一部分(其中RFC 3986未指定

上面的任何保留字符都可以在没有编码的URI中合法使用,既可以用于语法目的,也可以作为数据中的文字字符,在某些地方,这些使用不能被误解为服务于其语法目的的字符。 (例如,虽然/在URL中具有语法含义,但您可以在查询字符串中使用未编码的,因为 在查询字符串中没有意义。)

RFC 3986还指定了一些非保留字符,这些字符始终可以简单地用于表示数据而无需任何编码:

  • abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~

最后,允许使用%字符进行百分比编码。

只留下禁止的以下ASCII字符出现在网址中:

  • 控制字符(字符0-1F和7F),包括换行,制表符和回车符。
  • "<>\^`{|}

ASCII中的每个其他字符都可以合法地显示在URL中。

然后RFC 3987使用以下unicode字符范围扩展该组未保留字符:

  %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF
/ %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD
/ %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD
/ %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD
/ %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD
/ %xD0000-DFFFD / %xE1000-EFFFD

鉴于最新的Unicode data URIs,旧规范中的这些块选择看起来很奇怪和随意;这可能是因为在编写RFC 3987之后的十年中已经添加了块。

最后,或许值得注意的是,仅仅知道哪些字符可以合法地出现在URL中是不足以识别某些给定字符串是否是合法URL,因为某些字符仅在URL的特定部分是合法的。例如,保留字符[]作为block definitions之类的URL中的IPv6文字主机的一部分是合法的,但在任何其他上下文中都不合法,因此OP的示例为http://example.com/file[/].html是非法的。

答案 3 :(得分:19)

在您的补充质询中,您询问www.example.com/file[/].html是否为有效网址。

该URL无效,因为URL是一种URI,而有效URI必须具有http:之类的方案(请参阅RFC 3986)。

如果您打算询问http://www.example.com/file[/].html是否为有效网址,则答案仍然是否定,因为方括号字符在那里无效。

为此格式的网址保留方括号字符:http://[2001:db8:85a3::8a2e:370:7334]/foo/bar(即IPv6文字而非主机名)

如果你想完全理解这个问题,那么值得仔细阅读RFC 3986。

答案 4 :(得分:11)

可以在URI中使用的所有有效字符(URLURI的类型)在RFC 3986中定义。

所有其他字符都可以在URL中使用,前提是它们首先是“URL编码”。这涉及更改特定“代码”的无效字符(通常采用百分号(%)后跟十六进制数字的形式)。

此链接HTML URL Encoding Reference包含无效字符的编码列表。

答案 5 :(得分:9)

有几个Unicode字符范围是有效的HTML5 ,尽管使用它们可能仍然不是一个好主意。

例如,href文档说http://www.w3.org/TR/html5/links.html#attr-hyperlink-href

  

a和area元素的href属性必须具有可能被空格包围的有效URL值。

然后“有效网址”的定义指向http://url.spec.whatwg.org/,其中的目标是:

  

将RFC 3986和RFC 3987与当代实现保持一致,并在此过程中废弃它们。

该文件将URL code points定义为:

  

ASCII字母数字,“!”,“$”,“&amp;”,“'”,“(”,“)”,“*”,“+”,“,”,“ - ”,“。” ,“/”,“:”,“;”,“=”,“?”,“@”,“_”,“〜”以及范围U + 00A0到U + D7FF,U + E000中的代码点到U + FDCF,U + FDF​​0到U + FFFD,U + 10000到U + 1FFFD,U + 20000到U + 2FFFD,U + 30000到U + 3FFFD,U + 40000到U + 4FFFD,U + 50000到U + 5FFFD,U + 60000至U + 6FFFD,U + 70000至U + 7FFFD,U + 80000至U + 8FFFD,U + 90000至U + 9FFFD,U + A0000至U + AFFFD,U + B0000至U + BFFFD ,U + C0000至U + CFFFD,U + D0000至U + DFFFD,U + E1000至U + EFFFD,U + F0000至U + FFFFD,U + 100000至U + 10FFFD。

然后在语句中使用术语“URL代码点”:

  

如果c不是URL代码点而不是“%”,则解析错误。

在解析算法的几个部分中,包括模式,权限,相对路径,查询和片段状态:基本上是整个URL。

此外,验证程序http://validator.w3.org/会为"你好"等网址传递,并且不会传递包含空格"a b"等字符的网址

当然,正如Stephen C所提到的,它不仅仅是关于角色,还关系到背景:你必须要了解整个算法。但是,由于类“URL代码点”用于算法的关键点,因此可以很好地了解您可以使用或不使用的内容。

另请参阅:Unicode characters in URLs

答案 6 :(得分:5)

我需要选择字符来分割字符串中的url,所以我决定创建一个我自己无法在URL中找到的字符列表:

>>> allowed = "-_.~!*'();:@&=+$,/?%#[]?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
>>> from string import printable
>>> ''.join(set(printable).difference(set(allowed)))
'`" <\x0b\n\r\x0c\\\t{^}|>'

因此,可能的选择是换行符,制表符,空格,反斜杠和"<>{}^|。我想我会选择空格或换行符。 :)

答案 7 :(得分:4)

对你的问题不是一个真正的答案,但验证网址确实是一个严重的问题p.i.t.a 您可能只是更好地验证域名并留下URL的查询部分。这是我的经历。 您也可以使用ping网址,看看它是否会产生有效的响应,但这对于这么简单的任务来说可能太多了。

检测网址的正则表达式很丰富,google it :)。

答案 8 :(得分:1)

我正在实现旧的http(0.9,1.0,1.1)请求和响应读取器/写入器。请求URI是最有问题的地方。

您不能照原样使用RFC 1738、2396或3986。许多旧的HTTP客户端和服务器都允许使用更多字符。因此,我基于意外发布的Web服务器访问日志进行了研究:const obj3 = Math.random() < 0.5 ? obj : obj2; console.log(obj3.isMessage()); // just known as boolean now if (obj3.isMessage()) { obj3._input.type // "message" } else { obj3._input.type // "unknown" }

我发现URI中经常使用以下非标准字符:

"GET URI HTTP/1.0" 200

这些字符在 RFC 1738 中描述为不安全

如果要与所有旧的HTTP客户端和服务器兼容-必须在请求URI中允许这些字符

请在oghttp-request-collector中阅读有关此研究的更多信息。

答案 9 :(得分:-4)

我想出了一些PHP的正则表达式,它们将文本中的url转换为锚标记。 (首先它将所有www。网址转换为http://然后将所有网址转换为https?://转换为href = ... html链接

rake bower:install