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

时间:2010-03-02 19:51:24

标签: url query-string uri specifications

背景(问题进一步向下)

我一直在谷歌搜索这些来回阅读RFC和SO试图解决这个问题,但我仍然没有杰克。

所以我想我们只是投票选出“最佳”答案,就是这样,或者?

基本上归结为此。

  

3.4。查询组件

     

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

     

query = *uric

     

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

让我感到困惑的第一件事就是* uric就像这样定义了

  

uric = reserved | unreserved | escaped

     

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

然而,

等段落澄清了这一点
  

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

     

“保留”集中的字符不会在所有上下文中保留。实际上在任何给定URI组件中保留的字符集由该组件定义。通常,如果使用转义的US-ASCII编码替换字符,则URI的语义会发生变化,从而保留字符。

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

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

  

HTTP URL采用以下形式:

     

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

     

在&lt; path&gt;内和&lt; searchpart&gt;组件, ”/”, ”;”, ”?”保留。可以在HTTP中使用“/”字符来指定分层结构。

我至少对RFC 1738取代RFC 2396的HTTP URL进行了解释。因为URI查询没有查询字符串的概念,所以对reserved的解释实际上并不允许我定义查询字符串,因为我'我过去常常这样做。

问题

当我想将一个数字列表与另一个资源的请求一起传递时,这一切都开始了。我没有想太多,只是将它作为逗号分隔值传递给它。令我惊讶的是,逗号被逃脱了。查询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肯定不是参考实现,但它还没有让我失望。

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

7 个答案:

答案 0 :(得分:62)

在通用URL组件中保留字符并不意味着当它出现在组件内或组件中的数据中时必须进行转义。该字符还必须在泛型或特定于方案的语法中定义为分隔符,并且字符的外观必须在数据中。

通用URI的当前标准是RFC 3986,可以这样说:

2.2. Reserved Characters

URI包括由“reserved”集中的字符分隔的组件和子组件。这些字符称为“保留”,因为它们可能(或可能不)通过通用语法,每种特定于方案的语法或URI的解除引用算法的特定于实现的语法定义为分隔符。如果URI组件的数据与保留字符作为分隔符的目的冲突 [强调添加],则冲突数据必须在形成URI之前进行百分比编码。

   reserved    = gen-delims / sub-delims

   gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@"

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

3.3. Path Component

[...]
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
[...]

3.4 Query Component

[...]  
      query       = *( pchar / "/" / "?" )

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

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

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

2.2. Reserved Characters

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

由于逗号在HTTP方案下没有保留的目的,因此不必在数据中对其进行转义。第2.3节中关于保留字符的注释是在百分比编码时改变语义的注释,一般只适用;字符可以进行百分比编码而不改变特定方案的语义,但仍然保留。

答案 1 :(得分:16)

要回答查询字符串中的有效内容,我会在发出请求时检查哪些特殊字符被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中使用~,但它仍然是有效字符。

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

所以回答应该编码的内容:你想要字面处理但具有特殊含义的无效字符和字符,或者可能在服务器端造成麻烦。

答案 2 :(得分:9)

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

即可

我在这里回答第四个问题:)没有问但是所有问题都开始于:我如何传递数字列表a-la逗号分隔值?在我看来,最好的方法就是将它们以空格分隔,其中空格将以url-form编码为+。工作得很好,只要你知道列表中的值不包含空格(数字往往不会)。

答案 3 :(得分: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实现者支持使用“;”取代“&amp;”为作者省去逃避“&amp;”的麻烦这种方式的人物。

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

答案 4 :(得分:1)

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

在Classic 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=3a作为“1,2,3”。但我确信有一种方法可以获取每个单独的元素,以防元素本身包含逗号。它只是非索引QueryString的默认属性,它将子值与逗号分隔符连接在一起。

答案 5 :(得分:1)

我有同样的问题。已超链接的URL是第三方网址,并且只能使用格式page.html?q=1,2,3的参数列表,并且网址page.html?q=1%2C2%2C3不起作用。我能够使用javascript工作。可能不是最好的方法,但可以查看解决方案here,如果它可以帮助任何人。

答案 6 :(得分:-3)

如果您要将ENCODED字符发送到 FLASH / SWF 文件,那么您应该将字符ENCODE两次!! (因为Flash解析器)