查询字符串的正确编码是什么?

8
我正在尝试从asp.net应用程序发送请求到像这样的url“http://mysite.dk/tværs?test=æ”,但我在正确编码查询字符串方面遇到了麻烦。或者说,查询字符串已经正确编码,我连接的服务只是无法正确理解它。
我尝试使用不同的浏览器发送请求并使用Wireshark记录它们如何编码请求,结果如下:
Firefox: http://mysite.dk/tv%C3%A6rs?test=%E6 Ie8: http://mysite.dk/tv%C3%A6rs?test=\xe6 Curl: http://mysite.dk/tv\xe6rs?test=\xe6
Firefox、IE和Curl都从服务接收到了正确的结果。请注意,它们以不同的方式对丹麦特殊字符“æ”进行编码。
当我使用HttpWebRequest从我的asp.net应用程序发送请求时,URL被编码为:
http://mysite.dk/tv%C3%A6rs?test=%C3%A6
它将查询字符串与路径部分一样进行编码。远程服务无法理解此编码,因此我没有得到正确的答案。
顺便说一下,“æ”(U+00E6)在ISO-LATIN-1中为%E6,在UTF-8中为%C3%A6。
我可以更改远程服务以接受UTF-8编码的查询字符串,但那样服务将无法在浏览器中正常工作,我不太感兴趣。有没有一种方法可以指定.NET不应使用UTF-8对查询字符串进行编码?
我是这样创建webrequest的:
var req = WebRequest.Create("http://mysite.dk/tværs?test=æ") as HttpWebRequest;

但是问题似乎源于System.Uri,它显然在WebRequest.Create中被使用:

var uri = new Uri("http://mysite.dk/tværs?test=æ");
// now uri.AbsolutePath == "http://mysite.dk/tv%C3%A6rs?test=%C3%A6"

生成当前 http://mysite.dk/tv%C3%A6rs?hest=%C3%A6 的 ASP.NET 代码是什么? - Hari Pachuveetil
我非常确定UTF-8是正确的编码方式。但是似乎找不到权威来源来证实这一点。(RFC3986没有提到查询字符串;Wikipedia说:“对于非ASCII字符,通常将其转换为UTF-8中的字节序列,然后每个字节值都表示如上。”)。 - dtb
@dtb,是的,我也看到了那个问题,但似乎浏览器(和curl)已经一致决定使用latin1来编码查询字符串。我更喜欢在任何地方都使用UTF-8,但我也更希望支持浏览器在我的Web服务中... - AHM
1
似乎浏览器由于历史原因违反了规范(例如,请参见bugzilla.mozilla.org)。.NET的行为是正确的。简单的解决方案:不要使用查询字符串。(路径似乎可以正常工作。) - dtb
3个回答

5
看起来你正在对整个URL应用UrlEncode-这是不正确的,路径和查询字符串的编码方式是不同的,就像你已经看到的那样。进行URI编码的是什么,WebRequest吗?
你可以使用UriBuilder手动构建各个部分,或者手动使用UrlPathEncode进行路径编码,使用UrlEncode对查询字符串名称和值进行编码。
编辑:
如果问题出在路径而不是查询字符串上,你可以通过web.config打开IRI支持。
<configuration>
  <uri>
      <iriParsing enabled="true" />
  </uri>
</configuration>

那么,这应该能够让路径中的国际字符保持不变。

该服务返回charset=UTF8,并且接收它的HttpWebResponse对象正确确定了这一点。我不确定如何读取(或更改)请求对象上的字符集。UriBuilder可能是解决方法 - 我只是感到困惑,为什么没有某种标准来处理这个问题。 - AHM
尝试配置IRI(rfc3987)支持,这应该会保留路径不变,但我相信UTF8将是唯一支持的查询字符串编码,HTML4规范将其作为建议,并且它已经成为事实标准。 - blowdart

2

UrlEncode返回的是"http%3a%2f%2fmysite.dk%2ftv%c3%a6rs%3ftest%3d%c3%a6",完全是错误的。我可以在“?”上拆分字符串,并使用HttpUtility.UrlEncode(qstr,Encoding.GetEncoding("iso-8859-1"))对查询字符串进行编码,然后修复“&”和“;”字符,但这感觉更像是一种hack而不是解决方案... - AHM

0

我最终将我的远程 Web 服务更改为期望查询字符串采用 UTF-8 编码。这解决了我立即面临的问题,该 Web 服务无法正确地被 PHP 和 .NET Framework 调用。

然而,现在在浏览器中的行为变得奇怪了。将类似 "http://mysite.dk/tv%C3%A6rs?test=%C3%A6" 的 URL 复制粘贴到浏览器中,然后按回车键可以正常工作,它甚至会自动更正编码字符并显示位置为 "http://mysite.dk/tværs?test=æ"。如果重新加载页面(按下 F5),它仍然可以工作。但是,如果我单击位置栏并再次按回车键,查询字符串将使用 Latin-1 进行编码,导致失败。

对于任何感兴趣的人,这里有一个关于这个问题的旧 Firefox 报告:https://bugzilla.mozilla.org/show_bug.cgi?id=284474(感谢 @dtb)

所以,看来没有好的解决办法。

还是要感谢帮助过我的每个人!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接