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

背景(问题继续往下)

我一直在谷歌这来回阅读 RFC 和所以问题试图解决这个问题,但我仍然没有得到任何东西。

So I guess we just vote for the "best" answer and that's it, or?

基本上就是这样。

3.4. 查询组件

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

query = *uric

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

让我困惑的第一件事是尿液是这样定义的

uric = reserved | unreserved | escaped

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

This is however somewhat clarified by paragraphs such as

上面的“保留”语法类指的是 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

我的第二个问题,这是一个有效的 URL 吗?

我的回答,根据 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”时,我得到的是一个带有逗号的字符串。NET 当然不是一个参考实现,但它还没有让我失望。

但最重要的是——我的第三个问题——这方面的规范在哪里?你会做什么或者不做什么?

114015 次浏览

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

目前通用 URI 的标准是 RFC 3986,它的意思是:

2.2保留字符

URI 包括由“保留”集中的字符分隔的组件和子组件。这些字符被称为“保留”,因为它们可能(也可能不)被通用语法、每个方案特定的语法或 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       = *( pchar / "/" / "?" )

Thus commas are explicitly allowed within query strings and only need to be escaped in data if specific schemes define it as a delimiter. The HTTP scheme doesn't use the comma or semi-colon as a delimiter in query strings, so they don't need to be escaped. Whether browsers follow this standard is another matter.

Using CSV should work fine for string data, you just have to follow standard CSV conventions and either quote data or escape the commas with backslashes.

As for RFC 2396, it also allows for unescaped commas in HTTP query strings:

2.2. Reserved Characters

Many URI include components consisting of or delimited by, certain special characters. These characters are called "reserved", since their usage within the URI component is limited to their reserved purpose. If the data for a URI component would conflict with the reserved purpose, then the conflicting data must be escaped before forming the URI.

Since commas don't have a reserved purpose under the HTTP scheme, they don't have to be escaped in data. The note from § 2.3 about reserved characters being those that change semantics when percent-encoded applies only generally; characters may be percent-encoded without changing semantics for specific schemes and yet still be reserved.

Html? q = 1; q = 2; q = 3

这是一个有效的 URL 吗?

是的。;是保留的,但不是由 RFC 保留的。定义这个组件的上下文是 application/x-www-form-urlencoded媒体类型的定义,它是 HTML 标准的一部分(17.13.4.1部分)。特别是隐藏在 B2.2章节中的鬼鬼祟祟的笔记:

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

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

I would like to note that page.html?q=1&q=2&q=3 is a valid url as well. This is a completely legitimate way of expressing an array in a query string. Your server technology will determine how exactly that is presented.

In Classic ASP, you check Response.QueryString("q").Count and then use Response.QueryString("q")(0) (and (1) and (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 的默认属性,它将子值与逗号分隔符连接在一起。

?q=1+2+3

我在这里回答第四个问题:)这个问题并没有提出,但是一切都是从: 我如何通过 a-la 逗号分隔值的数字列表?在我看来,最好的方法就是将它们以空格分隔,这样空格就会以 url 格式编码为 +。工作得很好,只要你知道列表中的值不包含空格(数字通常不会包含空格)。

我也有同样的问题。被超链接的 URL 是第三方的 URL,并且希望获得格式为 page.html?q=1,2,3 ONLY 的参数列表,而 URL page.html?q=1%2C2%2C3不起作用。我可以用 javascript 让它工作。可能不是最好的方法,但可以检查解决方案 给你,如果它有助于任何人。

如果您将编码字符发送到 FLASH/SWF文件,那么您应该对该字符进行两次编码! !(因为有 Flash 解析器)

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

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

因此,要回答应该编码什么: 无效的字符和字符,您希望逐字处理,但有一个特殊的含义或可能导致在服务器端的麻烦。