URI查询中什么是有效的,什么不是?


100

背景(问题进一步)

我一直在来回搜索RFC和SO问题,以试图破解它,但我仍然没有得到杰克。

所以我想我们只是投票给“最佳”答案,仅此而已?

基本上可以归结为这一点。

3.4。查询组件

查询组件是由资源解释的信息字符串。

query = *uric

在查询组件中,保留字符“;”,“ /”,“?”,“:”,“ @”,“&”,“ =“,“ +”,“,”和“ $”。

让我感到困惑的第一件事是* uric定义如下

uric = reserved | unreserved | escaped

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

但是,这在某些段落中得到了澄清,例如

上面的“保留”语法类指的是URI中允许的那些字符,但是在通用URI语法的特定组件中可能不允许的那些字符;它们用作第3节中描述的组件的定界符。

并非在所有上下文中都保留“保留”集中的字符。在任何给定URI组件中实际保留的字符集由该组件定义。通常,如果将URI的语义更改为转义的US-ASCII编码,则保留该字符。

最后的摘录有些倒退,但是清楚地表明保留的字符集取决于上下文。但是3.4声明所有保留字符都保留在查询组件中,但是,唯一会改变此处语义的是转义问号(?),因为URI并未定义查询字符串的概念。

至此,我完全放弃了RFC,但发现RFC 1738特别有趣。

HTTP URL的形式为:

http://<host>:<port>/<path>?<searchpart>

在<path>和<searchpart>组件中,“ /”,“;”,“?” 保留。可以在HTTP中使用“ /”字符来指定层次结构。

我至少针对RFC 1738取代RFC 2396的HTTP URL对此进行解释。由于URI查询没有查询字符串的概念,因此对保留的解释也不允许我像以前那样定义查询字符串现在做。

当我想传递数字列表以及其他资源的请求时,一切就开始了。我没有考虑太多,只是将其作为逗号分隔的值传递。令我惊讶的是,尽管逗号已转义。查询page.html?q=1,2,3编码变成page.html?q=1%2C2%2C3可以使用,但是很丑陋,没想到。那是我开始阅读RFC的时候。

我的第一个问题很简单,是否真的需要编码逗号?

我的答案,根据RFC 2396:是的,根据RFC 1738:否

后来我找到了有关在请求之间传递列表的相关文章。csv方法被认为是不好的地方。而是出现了(以前没有见过)。

page.html?q=1;q=2;q=3

我的第二个问题,这是有效的网址吗?

我的答案,根据RFC 2396:否,根据RFC 1738:否(;保留)

只要有数字,我传递csv不会有任何问题,但是是的,如果确实突然需要使用逗号,那么您确实会冒着必须来回编码和解码值的风险。无论如何,我用ASP.NET尝试了分号查询字符串,结果却不是我所期望的。

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

我看不到这与csv方法有很大的不同,因为当我要求输入“ a”时,会得到一个带逗号的字符串。ASP.NET当然不是参考实现,但还没有让我失望。

但最重要的是-我的第三个问题-规范在哪里?而您会做什么或为此不会做什么?


当RFC 2396在将近4年后发布时,RFC 1738如何取代RFC 2396?
马修·弗莱申

1
关于URL及其实际意义,我的解释是这样做的。(但是superdede可能不是正确的词,因为RFC术语中已使用superdede来弃用旧的RFC,当RFC 1738是唯一的允许您将查询字符串放入searchpart的规范时,RFC 1738不会感到不赞成使用网址)
John Leidegren

Answers:


69

在通用URL组件中保留字符并不意味着在字符出现在组件中或组件中的数据中时必须对其进行转义。还必须在通用或特定于方案的语法中将字符定义为定界符,并且字符的外观必须在数据中。

通用URI的当前标准是RFC 3986,其含义如下:

2.2。保留字符

URI包括由“保留”集中的字符分隔的组件和子组件。这些字符之所以称为“保留”,是因为它们可能(也可能不会)通过通用语法,每种方案特定的语法或URI取消引用算法的实现特定的语法定义为定界符。如果URI组件的数据会与保留字符的目的(作为分隔符)加冲突(强调),那么在形成URI之前必须对冲突的数据进行百分比编码。

   保留= gen-delims / sub-delims

   gen-delims =“:” /“ /” /“?” /“#” /“ [” /“]” /“ @”

   sub-delims =“!” /“ $” /“&” /“'” /“(” /“)”
               /“ *” /“ +” /“,” /“;” /“ =”

3.3。路径分量

[...]
pchar =保留/ pct编码/ sub-delims /“:” /“ @”
[...]

3.4查询组件

[...]
      查询= *(pchar /“ /” /“?”)

因此,在查询字符串中明确允许使用逗号,并且仅当特定方案将其定义为定界符时才需要在数据中转义。HTTP方案不使用逗号或分号作为查询字符串中的定界符,因此不需要对其进行转义。浏览器是否遵循此标准是另一回事。

使用CSV应该可以很好地处理字符串数据,您只需遵循标准的CSV约定,并引用数据或使用反斜杠转义逗号即可。

对于RFC 2396,它还允许在HTTP查询字符串中使用未转义的逗号:

2.2。保留字符

许多URI包含由某些特殊字符组成或由其分隔的组件。这些字符称为“保留”,因为它们在URI组件中的使用仅限于其保留目的。如果URI组件的数据将与保留用途冲突,则必须在形成URI之前转义冲突的数据。

由于逗号在HTTP方案下没有保留的用途,因此不必在数据中进行转义。§2.3中有关保留字符的注释仅适用于通常使用百分比编码时会改变语义的字符;可以对字符进行百分比编码,而无需更改特定方案的语义,但仍然保留。


23

为了回答查询字符串中的有效内容,我检查了发出请求时哪些特殊字符被chrome替换了:

Space -> %20
! -> !
" -> %22
# -> removed, marks the end of the query string
% -> %
& -> &
' -> %27
( -> (
) -> )
* -> *
+ -> + (this usually means blank when received at the server, so encode if necessary)
, -> ,
- -> -
. -> .
/ -> /
: -> :
; -> ;
< -> %3C
= -> =
> -> %3E
? -> ?
@ -> @
[ -> [
\ -> \
] -> ]
^ -> ^
_ -> _
` -> `
{ -> {
| -> |
} -> }
~ -> ~

Extended ASCII (like °) -> Every character from this set is encoded

注意:这可能并不意味着您不应该在生成链接的URI时转义那些未被替换的字符。例如,~由于兼容性问题,通常建议不要在URI中使用它,但它仍然是有效字符。

另一个例子是加号,它是有效的,但是当服务器将其作为请求的一部分接收时,通常将其视为编码的空白。因此,即使目的是表示加号而不是空格,也应该对其进行编码,即使它是有效的。

因此,要回答应编码的内容:无效字符和您要按字面意义对待但具有特殊含义的字符,否则可能在服务器端造成麻烦。


/programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b#1;c#2有效的查询参数吗?
Sumit Jain

@SumitJain否,因为#不能原样出现在URI的查询部分内。您将需要将其编码为%23,因此URI应该是/programming/2366260/whats-valid-and-whats-not-in-a-uri-query?param=b%231;c%232

10

只需使用 ?q=1+2+3

我在这里回答第四个问题:)并没有问,但所有问题都始于:我如何传递数字列表,用逗号分隔值?在我看来,最好的方法是将它们传递以空格分隔,其中空格将以url形式编码为+。只要您知道列表中的值不包含空格(某些数字通常不包含空格),效果就很好。


虽然这应该是一个评论(因为它不能回答问题),但谢谢您。+在我要使用逗号的特定情况下,这更有意义。
加茹斯

6

page.html?q = 1; q = 2; q = 3

这是有效的网址吗?

是。将;被保留,而不是由一个RFC。定义此组件的上下文是application/x-www-form-urlencoded媒体类型的定义,它是HTML标准的一部分(第17.13.4.1节)。特别是B.2.2节中隐藏的偷偷摸摸的音符:

我们建议HTTP服务器实现者,尤其是CGI实现者支持使用“;”。代替“&”来节省作者用这种方式转义“&”字符的麻烦。

不幸的是,许多流行的服务器端脚本框架(包括ASP.NET)都不支持这种用法。


因此,在?q=1;q=2;q=3查询有效的同时,它还是模棱两可的:某些服务器端框架会将其读为{ q: '1;q=2;q=3' },其他则可能类似于{ q: {'1', '2', '3'}}
Nas Banov 2014年

1
是。更糟糕的是,HTML5现在不包含关于的语言;,这意味着HTML4和HTML5不一致。
gh,

@NasBanov还有其他人(例如PHP)将其解释为{ q: 3 }
Nicholas Shanks

1
@NicholasShanks-涉及PHP,所有赌注都关闭了!:)
Nas Banov

1

我想指出的是,这page.html?q=1&q=2&q=3也是一个有效的网址。这是在查询字符串中表达数组的完全合法的方法。您的服务器技术将确定显示的精确程度。

在经典ASP中,您检查Response.QueryString("q").Count然后使用Response.QueryString("q")(0)(以及(1)和(2))。

请注意,您也在ASP.NET中也看到了这一点(我认为这不是故意的,而是看起来):

Default.aspx?a=1;a=2&b=1&a=3

Request.QueryString["a"] = "1;a=2,3"
Request.QueryString["b"] = "1"

注意,分号被忽略,因此您a定义了两次,并且两次获得了它的值,并用逗号分隔。使用所有与号Default.aspx?a=1&a=2&b=1&a=3将产生a “与”号 “ 1、2、3”。但是我敢肯定,有一种方法可以获取每个单独的元素,以防元素本身包含逗号。只是非索引QueryString的默认属性将子值与逗号分隔符连接在一起。


1

我遇到过同样的问题。超链接的URL是第三方URL,并且仅期望格式列表中的参数,page.html?q=1,2,3并且该URL page.html?q=1%2C2%2C3不起作用。我能够使用javascript使其正常工作。可能不是最好的方法,但如果对任何人有帮助,都可以在此处查看解决方案。


-3

如果要将已编码的字符发送到FLASH / SWF文件中,则应两次编码该字符!!(由于Flash解析器)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.