分号作为 URL 查询分隔符
Posted
技术标签:
【中文标题】分号作为 URL 查询分隔符【英文标题】:Semicolon as URL query separator 【发布时间】:2011-03-29 17:48:14 【问题描述】:虽然强烈建议(W3C source,通过Wikipedia)Web 服务器支持分号作为 URL 查询项的分隔符(除了 & 符号),但似乎并不普遍遵循。
例如比较
http://www.google.com/search?q=nemo&oe=utf-8
http://www.google.com/search?q=nemo;oe=utf-8
结果。 (在后一种情况下,分号是,或在撰写本文时,被视为普通字符串字符,就好像 url 是:http://www.google.com/search?q=nemo%3Boe=utf-8)
虽然我尝试的第一个 URL 解析库表现良好:
>>> from urlparse import urlparse, query_qs
>>> url = 'http://www.google.com/search?q=nemo;oe=utf-8'
>>> parse_qs(urlparse(url).query)
'q': ['nemo'], 'oe': ['utf-8']
目前接受分号作为分隔符的状态如何,有哪些潜在问题或一些有趣的注意事项? (从服务器和客户端的角度来看)
【问题讨论】:
Google 搜索只做一件事——Golang 做相反的事情:github.com/golang/go/issues/2210 【参考方案1】:只要您的 HTTP 服务器和服务器端应用程序接受分号作为分隔符,您就可以开始使用了。我看不出有什么缺点。正如你所说,W3C spec is on your side:
我们建议 HTTP 服务器实现者,特别是 CGI 实现者支持使用“;”代替“&”来省去作者以这种方式转义“&”字符的麻烦。
【讨论】:
至少看到一个缺点 - 从客户的角度来看,我不能安全地决定在请求中使用;
而不是 &
(好的,我在客户对问题的观点)
@mykhal:“从客户端的角度来看”......您的意思是当您通过 Web 服务或类似服务公开 API 时?因为否则我认为通过网络浏览器使用网站的最终用户不应该关心。关于前者,是的,Web 服务消费者可能更习惯于使用 &
,并且可能会对这种不寻常的约定感到困惑。
@[Daniel Vassallo] 我的意思是,一般来说。顺便说一句,我隐含地解决了您在回答中提到的完全相同的 W3C 引用,因此这对我来说并不令人满意.. 没关系 :)
有缺点。通过给 ”;” RFC 中最初未指定的特殊附加含义,您强制使用“;”在键和值文本中进行转义。例如,?q='one;two'&x=1
。你会期待"q": "'one;two'", "x": "1"
,但很可能最终得到:"q": "'one", "two'": null, "x": "1"
或其他一些值。那里有很多潜在的歧义。基本上,W3C 是愚蠢的。
What do you do 在针对 an API that uses semicolons as delimiters like the StackExchange API 进行测试时?【参考方案2】:
我同意鲍勃·阿曼的观点。 W3C 规范旨在让锚超链接更容易与看起来像 GET 请求的 URL 一起使用(例如,http://www.host.com/?x=1&y=2
)。在这种情况下,& 符号与字符实体引用的系统冲突,它们都以 & 符号开头(例如,"
)。因此 W3C 建议 Web 服务器允许将分号用作字段分隔符而不是 & 符号,以便更轻松地编写这些 URL。但是这个解决方案要求编写者记住必须用某些东西替换与号,并且;
是同样有效的字段分隔符,即使 Web 浏览器在提交表单时普遍在 URL 中使用与号。这可以说比记住在这些链接中用&
替换&符号更困难,就像在文档中的其他地方所做的那样。
更糟糕的是,在所有 Web 服务器都允许使用分号作为字段分隔符之前,URL 编写者只能对某些主机使用此快捷方式,而对于其他主机则必须使用 &
。如果给定的主机停止允许分号分隔符,他们还必须稍后更改他们的代码。这肯定比简单地使用&
更难,后者将永远适用于每台服务器。这反过来又消除了 Web 服务器允许使用分号作为字段分隔符的任何动机。当每个人都已经将 & 符号更改为 &
而不是 ;
时,何必呢?
【讨论】:
我说继续只使用 & 而不允许两者都更难。我说允许想要更简单生活的人使用;会让他们更容易,因为有时一些网站需要了解这两种选项的相对简单的复杂性是值得的。 使用 & 分隔符处理 QueryStrings 比切换到 ; 复杂两倍以上分隔 QueryString 项。使用 ;大大减少了用于“&”的不正确 html endoced 字符串的潜在错误。 我想我听到 Matthias 说使用 '&' 作为分隔符更好,因为它们已经更流行了。我说,这是一个很好的观点。我并不是反对这一点。我想传达的是,如果我们 all 开始使用 ';'相反,从长远来看,这对大多数人来说更容易。我是说';' all 比 '&' 更好用。而且我还说,在所有人都切换到其中一个之前,我们只需要处理一个以不同方式做事的小组,所以如果我们想要健壮的代码,我们需要能够处理两者,不管.【参考方案3】:简而言之,HTML 是一团糟(由于它的宽大处理),使用分号有助于简化这一点。我估计,当我考虑到我发现的复杂情况时,使用 & 作为分隔符会使整个过程的复杂度大约是使用分号作为分隔符的三倍!
我是一名 .NET 程序员,据我所知,.NET 不天生就允许使用 ';'分隔符,所以我编写了自己的解析和处理方法,因为我看到了使用分号的巨大价值,而不是使用 & 符号作为分隔符已经存在问题的系统。不幸的是,非常受人尊敬的人(例如另一个答案中的@Bob Aman)没有看到为什么使用分号比使用&符号要优越得多且简单得多的价值。因此,我现在分享几点,或许可以说服其他尚未认识到使用分号的价值的可敬开发人员:
在 HTML 页面中使用像 '?a=1&b=2' 这样的查询字符串是不合适的(没有首先对其进行 HTML 编码),但大多数情况下它是有效的。然而,这只是因为大多数浏览器都具有容错性,并且这种容错性可能会导致难以发现的错误,例如,当键值对的值在没有正确编码的情况下发布在 HTML 页面 URL 中时(直接作为 '? HTML 源代码中的 a=1&b=2')。像 '?who=me+&+you' 这样的 QueryString 也是有问题的。
我们人可能有偏见,并且可能整天不同意我们的偏见,因此认识到我们的偏见非常重要。例如,我同意我只是想用';'分开看起来“更干净”。我同意我的“更清洁”意见纯粹是一种偏见。另一个开发人员可能有同样相反和同样有效的偏见。所以我对这一点的偏见并不比相反的偏见更正确。
但鉴于分号的公正支持从长远来看使每个人的生活更轻松,如果考虑到整体情况,则无法正确争论。简而言之,使用分号确实让每个人的生活变得更简单,但有一个例外:习惯新事物的一个小障碍。就这样。做出任何改变总是比较困难的。但与继续使用 & 的持续困难相比,做出改变的困难就相形见绌了。
使用 ;作为 QueryString 分隔符使它更简单。 正确编码与使用分号相比,与号分隔符的难度要高出两倍多。 (我认为)大多数实现都没有正确编码,所以大多数实现不会复杂两倍。但是随后追踪和修复错误会导致生产力下降。在这里,我指出当 & 是分隔符时正确编码 QueryString 所需的 2 个单独的编码步骤:
第 1 步:对查询字符串的键和值进行 URL 编码。 第 2 步:将第 1 步中的 URL 编码后的键和值(如“a=1&b=2”)连接起来。 第 3 步:然后在页面的 HTML 源中对整个 QueryString 进行 HTML 编码。因此,为了正确(无错误)的 URL 编码,必须进行两次特殊编码,不仅如此,而且编码是两种截然不同的不同编码类型。第一个是 URL 编码,第二个是 HTML 编码(用于 HTML 源代码)。如果其中任何一个不正确,那么我可以为您找到一个错误。但是对于 XML,第 3 步是不同的。对于 XML,则需要 XML 字符实体编码(几乎相同)。我的观点是,最后的编码取决于 URL 的上下文,无论是在 HTML 网页中还是在 XML 文档中。
现在有了更简单的分号分隔符,这个过程正如我们所期望的那样:
1:URL 对键和值进行编码, 2:将值连接在一起。 (第 3 步没有编码。)我认为大多数 Web 开发人员会跳过第 3 步,因为浏览器非常宽松。但这会导致错误和更多复杂性,在寻找这些错误或如果这些错误不存在时用户无法执行操作,或编写错误报告等时。
实际使用中的另一个复杂情况是在我的 C# 和 VB.NET 源代码中编写 XML 文档标记时。由于必须对 & 进行编码,因此从字面上看,这对我的工作效率来说是一个真正的拖累。额外的步骤 3 也使阅读源代码变得更加困难。因此,这种难以阅读的缺陷不仅适用于 HTML 和 XML,还适用于 C# 和 VB.NET 代码等其他应用程序,因为它们的文档使用 XML 文档。因此,第 3 步的编码复杂性也会扩散到其他应用程序。
总之,使用 ;作为分隔符很简单,因为使用分号时的(正确)过程是人们通常期望的过程:只需要进行一个编码步骤。
也许这并不太令人困惑。但是所有的混乱或困难都是由于使用了一个应该是 HTML 编码的分隔符。因此'&'是罪魁祸首。分号可以解决所有这些复杂问题。
(我会指出,我上面的 3 步与 2 步流程通常大多数应用程序需要多少步。但是,对于完全健壮的代码,无论使用哪种分隔符,都需要所有 3 个步骤。但根据我的经验,大多数实现是草率且不健壮的。因此,使用分号作为查询字符串分隔符将使更多人的生活更轻松,网站更少,并且互操作错误,如果每个人都默认使用分号而不是 & 号。)
【讨论】:
因此,在一定程度上,W3C 的手被束缚了,因为它继承了 SGML 实体引用语法,并且 URL 语法已经在其他地方进行了类似的定义。但是,在规范之外重新定义规范的行为对于有效的互操作来说是最糟糕的做法。假设我是规范实施者。我通读了规范,并准确而完美地实现了它。理想情况下,我应该能够与其他做过同样事情的人进行互操作。但是一旦我们中的一个人加入了额外的规则,就不再有互操作性了。这就是 W3C 错的原因。 另外,FWIW,源代码 cmets 中的 XML 也很愚蠢。不过那个不在 W3C 上。 @BobAman 您声称“一旦我们中的一个人加入了附加规则,就不再有互操作性了。”但这不是事实。这就像说如果您的服务器使用 POP3 而我的服务器仅使用 IMAP,则没有更多的互操作性,所以写 IMAP 的人是错误的。伙计,这被称为以更好的替代品添加技术。 IMAP 问题的解决方案与 ; 的解决方案相同。 URL 中的分隔符:注意两者,并使用服务器使用的那个。没有混乱。你让它变得比现在更难。旧技术因新标准而过时。这是其中之一。 所以鲍勃,我问你为什么缺乏互操作性?一个人仅限于使用 only 服务器本身使用的分隔符,无论网络服务器使用哪个字符。的美丽;与使用 & 号相比有几个优点: & 号需要额外的编码,而这在现实中几乎没有完成,我在回复中解释了这一点。所以我什至看不到一种方式;不如使用 & 号,除了一些服务器在实施方面落后于更新更好的选择。如此多的人仅仅因为它是新的东西而拒绝它,这从来没有让我感到惊讶。 您似乎对互操作的含义感到困惑。标准机构通常需要至少两个由不同方编写的可互操作的实现。如果客户端和服务器是由同一个人编写的,则它不是互操作的。 “选择与服务器相同的分隔符”根本不是互操作的。规范的全部意义在于,我应该确切地知道如何根据规范中给出的规则来解释一段数据。如果我需要知道您是否支持不同的分隔符,那就是“带外”,它不再是真正的互操作了。【参考方案4】:W3C Recommendation from 1999 已过时。根据2014 W3C Recommendation,目前的状态是分号现在非法作为参数分隔符:
要解码 application/x-www-form-urlencoded 有效载荷,应使用以下算法。 [...] 该算法的输出是名称-值对的排序列表。 [...]
让字符串成为将字符串有效负载严格拆分为 U+0026 AMPERSAND 字符 (&) 的结果。
换句话说,?foo=bar;baz
表示参数foo
将具有值bar;baz
;而?foo=bar;baz=sna
应该导致foo
成为bar;baz=sna
(虽然技术上是非法的,因为第二个=
应该转义为%3D
)。
【讨论】:
这个答案具有误导性,因为它严格地谈论表单编码,这不是 OP 所要求的,也不是包含的示例。表单 url 编码非常古老,在通过 如果您阅读 HTTP 和 URL 标准,您会发现它们没有为查询字符串定义任何语法,除了转义。事实上,提到的两个文档是现有查询参数的唯一规范。虽然您在技术上正确地认为表单编码(两个 W3C 建议都描述)与 POST 请求相关,但没有类似的 GET 规范,因此浏览器实现遵循前者。现代框架(例如 Mojolicious)也在放弃对分号分隔符的支持,除非所有浏览器都被重写,否则&符号将永远不会消失。 至于向 AJAX 发展,不要认为当前的 Swagger(又名 OpenAPI)标准只允许与号分隔的参数;分号只允许作为路径或 cookie 参数。如果您设计的 API 与 Swagger 规范相矛盾,那么您就有问题了。 当然规范没有定义分隔符。使用;
来分隔参数由我们自己做出明智的决定,这样我们就不必转义在放置在 html 属性中的 URL 中常见的参数。我们也可以在脚下射击自己并使用&
,然后在 HTML 属性中进行转义。我不怪 Swagger。毕竟,他们希望他们的服务能够在尽可能多的服务器上工作,所以他们选择了最弱的公分母。因此,如果您的 Web 服务器支持分号并且您正在编写自己的 URL,那么比其他人更聪明:使用分号。
我陷入浏览器兼容性问题,我的 s3 图像链接需要参数 X-Amz-SignedHeaders: content-type;host
,它适用于 chrome/firefox 和最新的 safari 浏览器,但在 Microsoft Edge 和 IE 11 上失败,任何建议我该如何解决这个问题以上是关于分号作为 URL 查询分隔符的主要内容,如果未能解决你的问题,请参考以下文章