提问人:good 提问时间:10/10/2009 最后编辑:Michał Perłakowskigood 更新时间:4/8/2023 访问量:683686
哪些字符会使 URL 无效?
Which characters make a URL invalid?
问:
哪些字符会使 URL 无效?
这些是有效的 URL 吗?
example.com/file[/].html
http://example.com/file[/].html
答:
这并不是您问题的答案,但验证 URL 确实是一个严肃的 p.i.t.a。您可能最好验证域名并保留 URL 的查询部分。这是我的经验。
您也可以求助于pingURL并查看它是否产生有效的响应,但对于如此简单的任务来说,这可能太多了。
检测URL的正则表达式很丰富,谷歌一下:)
评论
可在 URI(URL 是 URI 的一种类型)中使用的所有有效字符都在 RFC 3986 中定义。
所有其他字符都可以在 URL 中使用,前提是它们首先是“URL 编码”。这涉及更改特定“代码”的无效字符(通常以百分号 (%) 后跟十六进制数的形式)。
此链接(HTML URL 编码参考)包含无效字符的编码列表。
评论
通常,RFC 3986 定义的 URI(请参阅第 2 节:字符)可以包含以下 84 个字符中的任何一个:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=
请注意,此列表未说明这些字符在 URI 中可能出现的位置。
任何其他字符都需要使用百分比编码 (hh
) 进行编码。URI 的每个部分对需要由百分比编码的单词表示的字符都有进一步的限制。%
评论
/^([!#$&-;=?-[]_a-z~]|%[0-9a-fA-F]{2})+$/
在您的补充问题中,您询问了 URL 是否有效。www.example.com/file[/].html
该 URL 无效,因为 URL 是一种 URI 类型,并且有效的 URI 必须具有类似 (请参阅 RFC 3986) 的方案。http:
如果你打算问是否是一个有效的URL,那么答案仍然是否定的,因为方括号字符在那里是无效的。http://www.example.com/file[/].html
方括号字符保留用于以下格式的 URL:(即 IPv6 文本而不是主机名)http://[2001:db8:85a3::8a2e:370:7334]/foo/bar
如果您想完全了解该问题,值得仔细阅读 RFC 3986。
评论
[
]
http://example.com/file[/].html
此示例中的“[”和“]”是“不明智”的字符,但仍然是合法的。如果 [] 中的“/”是文件名的一部分,那么它是无效的,因为“/”是保留的,应该正确编码:
http://example.com/file[/].html
为了澄清并直接解决上述问题,有几类字符会导致 URL 和 URI 出现问题。
有些字符是不允许的,不应该出现在 URL/URI 中,保留字符(如下所述)和其他字符在某些情况下可能会导致问题,但被标记为“不明智”或“不安全”。RFC-1738 (URL) 和 RFC-2396 (URI) 中清楚地说明了为什么字符受到限制。请注意,较新的 RFC-3986(对 RFC-1738 的更新)定义了在给定上下文中允许哪些字符的构造,但较旧的规范提供了更简单、更通用的描述,说明以下规则不允许使用哪些字符。
URI 语法中不允许排除的 US-ASCII 字符:
control = <US-ASCII coded characters 00-1F and 7F hexadecimal>
space = <US-ASCII coded character 20 hexadecimal>
delims = "<" | ">" | "#" | "%" | <">
字符“#”被排除在外,因为它用于从片段标识符分隔 URI。百分号字符“%”被排除在外,因为它用于对转义字符进行编码。换句话说,“#”和“%”是必须在特定上下文中使用的保留字符。
允许列出不明智的字符,但可能会导致问题:
unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`"
在查询组件中保留和/或在 URI/URL 中具有特殊含义的字符:
reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
上面的“保留”语法类是指 URI 中允许的字符,但在泛型 URI 语法的特定组件中可能不允许的字符。“保留”集中的字符并非在所有上下文中都保留。例如,主机名可以包含可选的用户名,因此它可以类似于“@”字符具有特殊含义的地方。ftp://user@hostname/
下面是一个包含无效和不明智字符(例如 '$'、'['、']')且应正确编码的 URL 示例:
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,因此不允许使用 URL like 并且必须进行编码,就像使用 Java 和 URI 对象实例一样。http://api.google.com/q?exp=a|b
http://api.google.com/q?exp=a%7Cb
评论
?
@
%25
%7C
我需要选择字符来拆分字符串中的 URL,因此我决定创建一个自己在 URL 中找不到的字符列表:
>>> allowed = "-_.~!*'();:@&=+$,/?%#[]?@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
>>> from string import printable
>>> ''.join(set(printable).difference(set(allowed)))
'`" <\x0b\n\r\x0c\\\t{^}|>'
因此,可能的选择是换行符、制表符、空格、反斜杠和 .我想我会用空格或换行符。:)"<>{}^|
一些 Unicode 字符范围是有效的 HTML5,尽管使用它们可能仍然不是一个好主意。
例如,文档说 http://www.w3.org/TR/html5/links.html#attr-hyperlink-href:href
和 area 元素的 href 属性必须具有一个值,该值是可能被空格包围的有效 URL。
然后,“有效 URL”的定义指向 http://url.spec.whatwg.org/,它表示它旨在:
使 RFC 3986 和 RFC 3987 与现代实现保持一致,并在此过程中淘汰它们。
该文档将 URL 代码点定义为:
ASCII 字母数字、“!”、“$”、“&”、“'”、“(”、“)”、“*”、“+”、“-”、“.”、“/”、“:”、“;”、“=”、“”?“、”@“、”_“、”~“以及 U+00A0 到 U+D7FF、U+E000 到 U+FDCF、U+FDF0 到 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+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/ 传递 URL (如 ),并且不会传递带有空格等字符的 URL"你好"
"a b"
当然,正如 Stephen C 所提到的,这不仅与角色有关,还与上下文有关:您必须了解整个算法。但是,由于类“URL 代码点”用于算法的关键点,因此可以很好地了解您可以使用或不可以使用的内容。
另请参阅:URL 中的 Unicode 字符
这里的大多数现有答案都是不切实际的,因为它们完全忽略了地址的实际用法,例如:
首先,对术语的题外话。这些地址是什么?它们是有效的 URL 吗?
从历史上看,答案是否定的。根据 RFC 3986,从 2005 年开始,此类地址不是 URI(因此不是 URL,因为 URL 是一种 URI)。根据 2005 年 IETF 标准的术语,我们应该正确地将它们称为 IRI(国际化资源标识符),如 RFC 3987 中所定义的那样,从技术上讲,它们不是 URI,但只需对 IRI 中的所有非 ASCII 字符进行百分比编码即可转换为 URI。
根据现代规范,答案是“是”。WHATWG Living Standard 只是将以前称为“URI”或“IRI”的所有内容归类为“URL”。这使规范术语与未阅读规范的普通人使用“URL”一词的方式保持一致,这是规范的目标之一。
WHATWG生活标准允许哪些角色?
根据“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 代码点”列表不包括 ,但如果它们是百分比编码序列的一部分,则允许在“URL 代码单元”中使用 。%
%
我唯一能找到规范允许使用此集合中未包含的任何字符的地方是主机,其中 IPv6 地址包含在 和 字符中。在 URL 中的其他任何地方,要么允许使用 URL 单元,要么允许使用一些限制性更强的字符集。[
]
旧 RFC 允许使用哪些字符?
为了历史的缘故,并且由于此处的答案中没有在其他地方充分探讨它,因此让我们检查一下在较旧的规范对下是否允许。
首先,我们有两种类型的 RFC 3986 保留字符:
:/?#[]@
,它们是 RFC 3986 中定义的 URI 的泛型语法的一部分!$&'()*+,;=,
它们不是 RFC 通用语法的一部分,但保留用作特定 URI 方案的语法组件。例如,分号和逗号用作数据 URI 语法的一部分,并用作查询字符串中普遍存在的格式(RFC 3986 未指定)的一部分。&
=
?foo=bar&qux=baz
上述任何保留字符都可以在不进行编码的情况下合法地在 URI 中使用,以服务于其语法目的,或者在某些地方作为数据中的文字字符,在这种情况下,这种使用不会被误解为字符服务于其语法目的。(例如,尽管 URL 中具有语法含义,但可以在查询字符串中以未编码的方式使用它,因为它在查询字符串中没有含义。/
RFC 3986 还指定了一些未保留的字符,这些字符始终可以简单地用于表示数据,而无需任何编码:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~
最后,允许字符本身进行百分比编码。%
这样就只剩下以下禁止出现在 URL 中的 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 块定义,旧规范中的这些块选择似乎很奇怪且任意;这可能是因为自 RFC 3987 编写以来的十年中添加了这些块。
最后,可能值得注意的是,仅仅知道哪些字符可以合法地出现在 URL 中并不足以识别某些给定字符串是否是合法 URL,因为某些字符仅在 URL 的特定部分是合法的。例如,保留字符 和 作为 URL 中 IPv6 文本主机的一部分是合法的,例如 http://[1080::8:800:200C:417A]/foo,但在任何其他上下文中都是不合法的,因此 OP 的示例是非法的。[
]
http://example.com/file[/].html
评论
"<>\^`{|}
不是被禁止的,它们被标记为不安全。但这些字符经常在现实世界中使用。
=
key=value
=
&
foo=bar
====foo====bar====
!?@!?@
key=value
key=value
我想出了几个PHP的正则表达式,可以将文本中的URL转换为锚标记。(首先,它转换所有 www.URL 转换为 http://,然后将所有带有 https?:// 的 URL 转换为 href=...HTML 链接
$string = preg_replace('/(https?:\/\/)([!#$&-;=?\-\[\]_a-z~%]+)/sim', '<a href="$1$2">$2</a>', preg_replace('/(\s)((www\.)([!#$&-;=?\-\[\]_a-z~%]+))/sim', '$1http://$2', $string) );
评论
我正在实现一个旧的 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 中阅读有关此研究的更多信息。
评论
我不能对上面的答案发表评论,但想强调一点(在另一个答案中),即不允许到处都允许字符。例如,域名不能有下划线,因此 http://test_url.com 无效。
从源头(需要时添加强调):
不安全的:
由于多种原因,角色可能不安全。空格字符是不安全的,因为在转录或排版 URL 或进行文字处理程序处理时,重要的空格可能会消失,并且可能会引入无关紧要的空格。
字符“<”和“>”是不安全的,因为它们被用作 自由文本中 URL 周围的分隔符;引号 (“”“) 用于 在某些系统中分隔 URL。字符“#”不安全,应该 始终进行编码,因为它用于万维网和其他 系统从片段/锚标识符中分隔 URL,该标识符可能 跟着它。字符“%”是不安全的,因为它用于 其他字符的编码。其他角色不安全,因为 众所周知,网关和其他传输代理有时会修改 字符。这些字符是 “{”, “}”, “|”, “”, “^”, “~”, “[”, “]”和“'”。
所有不安全的字符必须始终在 URL 中编码。为 例如,即使在系统中,字符“#”也必须在 URL 中编码 通常不处理片段或锚点标识符,因此 如果将 URL 复制到另一个使用它们的系统中,它将 不需要更改 URL 编码。源
如果您需要进行更广泛的验证,包括表情符号(现在在 URL 中偶尔使用),例如:
http://factmyth.com/factoids/you-👏-can-👏-put-👏表情符号-👏 in-👏-urls-👏/
甚至在域名中,例如:😉.tld
那么这是一个有用的正则表达式:
[-a-zA-Z0-9\u1F60-\uFFFF@:%_\+.~#?&//=!'(),;*\$\[\]]*
PS :它不适用于编程语言中使用的所有正则表达式“风格”。它对 Python、Rust、Golang、现代 Javascript 有效,但对 PHP 无效。通过选择左侧的“flavors”并检查错误消息来检查此处:https://regex101.com/
评论