哪些字符使URL无效?

这些url是否有效?

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


当前回答

大多数现有的答案都是不切实际的,因为它们完全忽略了地址在现实世界中的用法,比如:

https://en.wikipedia.org/wiki/Mobius_strip or https://zh.wikipedia.org/wiki/Wikipedia: about the Chinese wikipedia/en.

首先,进入术语。这些地址是什么?它们是有效的url吗?

从历史上看,答案是“不”。根据RFC 3986,从2005年开始,这样的地址不是uri(因此也不是url,因为url是uri的一种)。根据2005 IETF标准的术语,我们应该正确地称它们为IRI(国际化资源标识符),如RFC 3987中定义的那样,它们在技术上不是uri,但可以通过简单地对IRI中的所有非ascii字符进行百分比编码来转换为uri。

根据现代规范,答案是“是的”。WHATWG生活标准简单地将以前被称为“uri”或“iri”的东西归类为“url”。这使规范术语与没有阅读规范的普通人使用“URL”这个词的方式保持一致,这是规范的目标之一。

WHATWG生活标准下允许哪些角色?

根据“URL”的新含义,允许使用哪些字符?在URL的许多部分,例如查询字符串和路径,我们被允许使用任意的“URL单位”,它们是

URL代码点和百分比编码的字节。

什么是“URL代码点”?

URL代码点是ASCII字母数字,U+0021 (!), U+0024 ($), U+0026 (&), U+0027 ('), U+0028左括号,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范围内的代码点,包括,不包括代理和非字符。

(请注意,“URL代码点”列表不包括%,但如果%s是百分比编码序列的一部分,则允许在“URL代码单位”中使用%s。)

我能发现的唯一一个规范允许使用不在这个集合中的任何字符的地方是在主机中,其中IPv6地址包含在[和]字符中。URL中的其他地方,要么允许URL单位,要么使用一些更严格的字符集。

旧的rfc允许哪些字符?

出于历史的考虑,由于在这里的答案中没有充分探讨,让我们检查一下旧眼镜下允许的情况。

首先,我们有两种类型的RFC 3986保留字符:

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

上面的任何保留字符都可以在URI中合法地使用而不进行编码,可以用于它们的语法目的,也可以作为数据中的文字字符,在某些地方这样的使用不会被误解为用于其语法目的的字符。(例如,尽管/在URL中具有语法意义,但您可以在查询字符串中使用它,因为它在查询字符串中没有意义。)

RFC 3986还指定了一些无保留字符,它们总是可以简单地用来表示没有任何编码的数据:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 - _ ~

最后,允许%字符本身用于百分比编码。

这样就只留下以下ASCII字符被禁止出现在URL中:

控制字符(字符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块定义,旧规范中的这些块选择看起来很奇怪,很随意;这可能是因为这些块是在RFC 3987编写后的十年中添加的。


最后,也许值得注意的是,仅仅知道哪些字符可以合法地出现在URL中还不足以识别某个给定的字符串是否是合法的URL,因为有些字符只在URL的特定部分合法。例如,保留字符[和]在像http://[1080::8:800:200C:417A]/foo这样的URL中作为IPv6字面主机的一部分是合法的,但在任何其他上下文中都是不合法的,因此OP的例子http://example.com/file[/].html是非法的。

其他回答

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

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

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

那么“有效URL”的定义指向http://url.spec.whatwg.org/,它说它的目标是:

将RFC 3986和RFC 3987与当代实现对齐,并在此过程中淘汰它们。

该文档将URL代码点定义为:

ASCII alphanumeric, "!", "$", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "=", "?", "@", "_", "~", and code points in the ranges U+00A0 to U+D7FF, U+E000 to U+FDCF, U+FDF0 to U+FFFD, U+10000 to U+1FFFD, U+20000 to U+2FFFD, U+30000 to U+3FFFD, U+40000 to U+4FFFD, U+50000 to U+5FFFD, U+60000 to U+6FFFD, U+70000 to U+7FFFD, U+80000 to U+8FFFD, U+90000 to U+9FFFD, U+A0000 to U+AFFFD, U+B0000 to U+BFFFD, U+C0000 to U+CFFFD, U+D0000 to U+DFFFD, U+E1000 to U+EFFFD, U+F0000 to U+FFFFD, U+100000 to U+10FFFD.

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

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

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

同样,验证器http://validator.w3.org/会通过“你好”这样的url,而不会通过像空格“a b”这样的字符的url

当然,正如Stephen C所提到的,这不仅与字符有关,还与上下文有关:你必须理解整个算法。但由于类“URL代码点”用于算法的关键点,它提供了一个很好的想法,你可以使用或不使用。

请参见:url中的Unicode字符

在你的补充问题中,你问www.example.com/file[/].html是否是一个有效的URL。

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

如果你想问http://www.example.com/file[/].html是否是一个有效的URL,那么答案仍然是否定的,因为方括号字符在那里是无效的。

方括号字符为如下格式的url保留:http://[2001:db8:85a3::8a2e:370:7334]/foo/bar(即IPv6文字而不是主机名)

如果您想全面理解这个问题,值得仔细阅读RFC 3986。

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

你不能只使用RFC 1738、2396或3986。有许多旧的HTTP客户端和服务器允许更多的字符。因此,我根据意外发布的web服务器访问日志进行了研究:“GET URI HTTP/1.0”200。

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

\ { } < > | ` ^ "

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

如果你想兼容所有旧的HTTP客户端和服务器,你必须允许这些字符出现在请求URI中。

请在oghttp-request-collector中阅读更多关于这项研究的信息。

通常,RFC 3986定义的uri(参见章节2:字符)可以包含以下84个字符中的任意一个:

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

注意,这个列表没有说明这些字符可能出现在URI中的哪个位置。

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

大多数现有的答案都是不切实际的,因为它们完全忽略了地址在现实世界中的用法,比如:

https://en.wikipedia.org/wiki/Mobius_strip or https://zh.wikipedia.org/wiki/Wikipedia: about the Chinese wikipedia/en.

首先,进入术语。这些地址是什么?它们是有效的url吗?

从历史上看,答案是“不”。根据RFC 3986,从2005年开始,这样的地址不是uri(因此也不是url,因为url是uri的一种)。根据2005 IETF标准的术语,我们应该正确地称它们为IRI(国际化资源标识符),如RFC 3987中定义的那样,它们在技术上不是uri,但可以通过简单地对IRI中的所有非ascii字符进行百分比编码来转换为uri。

根据现代规范,答案是“是的”。WHATWG生活标准简单地将以前被称为“uri”或“iri”的东西归类为“url”。这使规范术语与没有阅读规范的普通人使用“URL”这个词的方式保持一致,这是规范的目标之一。

WHATWG生活标准下允许哪些角色?

根据“URL”的新含义,允许使用哪些字符?在URL的许多部分,例如查询字符串和路径,我们被允许使用任意的“URL单位”,它们是

URL代码点和百分比编码的字节。

什么是“URL代码点”?

URL代码点是ASCII字母数字,U+0021 (!), U+0024 ($), U+0026 (&), U+0027 ('), U+0028左括号,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范围内的代码点,包括,不包括代理和非字符。

(请注意,“URL代码点”列表不包括%,但如果%s是百分比编码序列的一部分,则允许在“URL代码单位”中使用%s。)

我能发现的唯一一个规范允许使用不在这个集合中的任何字符的地方是在主机中,其中IPv6地址包含在[和]字符中。URL中的其他地方,要么允许URL单位,要么使用一些更严格的字符集。

旧的rfc允许哪些字符?

出于历史的考虑,由于在这里的答案中没有充分探讨,让我们检查一下旧眼镜下允许的情况。

首先,我们有两种类型的RFC 3986保留字符:

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

上面的任何保留字符都可以在URI中合法地使用而不进行编码,可以用于它们的语法目的,也可以作为数据中的文字字符,在某些地方这样的使用不会被误解为用于其语法目的的字符。(例如,尽管/在URL中具有语法意义,但您可以在查询字符串中使用它,因为它在查询字符串中没有意义。)

RFC 3986还指定了一些无保留字符,它们总是可以简单地用来表示没有任何编码的数据:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 - _ ~

最后,允许%字符本身用于百分比编码。

这样就只留下以下ASCII字符被禁止出现在URL中:

控制字符(字符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块定义,旧规范中的这些块选择看起来很奇怪,很随意;这可能是因为这些块是在RFC 3987编写后的十年中添加的。


最后,也许值得注意的是,仅仅知道哪些字符可以合法地出现在URL中还不足以识别某个给定的字符串是否是合法的URL,因为有些字符只在URL的特定部分合法。例如,保留字符[和]在像http://[1080::8:800:200C:417A]/foo这样的URL中作为IPv6字面主机的一部分是合法的,但在任何其他上下文中都是不合法的,因此OP的例子http://example.com/file[/].html是非法的。