C# WebRequest.getResponse(): 400 Bad Request

9
我正在尝试使用System.Web从服务器下载文件,它确实可以工作,但是某些链接会给我带来麻烦。这些链接看起来像这样:
http://cdn.somesite.com/r1KH3Z%2FaMY6kLQ9Y4nVxYtlfrcewvKO9HLTCUBjU8IBAYnA3vzE1LGrkqMrR9Nh3jTMVFZzC7mxMBeNK5uY3nx5K0MjUaegM3crVpFNGk6a6TW6NJ3hnlvFuaugE65SQ4yM5754BM%2BLagqYvwvLAhG3DKU9SGUI54UAq3dwMDU%2BMl9lUO18hJF3OtzKiQfrC/the_file.ext

代码基本上看起来像这样:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(link);
WebResponse response = request.getResponse();

getResponse()总是会抛出异常(错误400 Bad Request)。 但是我知道这个链接是有效的,因为我可以使用Firefox下载文件而没有任何问题。

我还尝试使用Uri.UnescapeDataString(link)解码链接,但是那个链接甚至在Firefox中也无法工作。

其他链接按照这种方式都可以正常工作。只有这些链接不行。

编辑:

好的,我使用Wireshark发现了一些东西:

如果我使用Firefox打开链接,将发送以下内容:

&ME3@"dM*PNyAo PA:]GET /r1KH3Z%2FaMY6kLQ9Y4nVxYp5DyNc49t5kJBybvjbcsJJZ0IUJBtBWCgri3zfTERQught6S8ws1a%2BCo0RS5w3KTmbL7i5yytRpn2QELEPUXZTGYWbAg5eyGO2yIIbmGOcFP41WdrFRFcfk4hAIyZ7rs4QgbudzcrJivrAaOTYkEnozqmdoSCCY8yb1i22YtEAV/epd_outpost_12adb.flv HTTP/1.1
Host: cdn.somesite.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive

我认为只有第一行存在问题,因为WebRequest.Create(link)会对URL进行解码:

&MEz.@!dM/nP9@~P>.GET /r1KH3Z/aMY6kLQ9Y4nVxYp5DyNc49t5kJBybvjbcsJJZ0IUJBtBWCgri3zfTERQught6S8ws1a%2BCo0RS5w3KTmbL7i5yytRpn2QELEPUXZTGYWbAg5eyGO2yIIbmGOcFP41WdrFRFcfk4hAIyZ7rs6Mmh1EsQQ4vJVYUwtbLBDNx9AwCHlWDfzfSWIHzaaIo/epd_outpost_12adb.flv HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20100101 Firefox/12.0
Host: cdn.somesite.com

( %2F将被替换为 / )

另一个编辑:

我发现 Uri 类会自动解码 url: Uri uri = new Uri(link); //link 没有被解码 Debug.WriteLine(uri.ToString()); //这里链接被解码了。

我该如何防止这种情况?

提前感谢您的帮助。


3
如果您不提供真实的URL,很难确定。尝试查看浏览器获取响应时的通信(使用Live HTTP头插件或类似Wireshark的工具)-这应该可以提示您在请求中要更改什么。 - voidengine
Uri类可以做到这一点,它有一个带有dontEscape参数的构造函数,但它已经过时并且不起作用。 - Antonio Bakula
谢谢,我刚刚发现这个问题。有没有办法防止它再次发生? - Pasukaru
2个回答

20
默认情况下,Uri类不允许在URI中使用转义的/字符(即使在我的阅读RFC 3986中似乎是合法的)。
Uri uri = new Uri("http://example.com/embed%2fded");
Console.WriteLine(uri.AbsoluteUri); // prints: http://example.com/embed/ded

(注意:不要使用Uri.ToString来打印URI。)
根据Microsoft Connect上的此问题的错误报告,这种行为是设计如此的,但您可以通过将以下内容添加到您的app.config或web.config文件中来解决它:
<uri>
  <schemeSettings>
    <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
  </schemeSettings>
</uri>

(由于WebRequest.Create(string)只是委托给WebRequest.Create(Uri),因此无论调用哪种方法,您都需要使用此解决方法。)

1
非常感谢!这解决了我的问题。还有感谢 Uri.ToString() 的提示。 - Pasukaru

3
在.NET 4.5中,这种情况已经发生了变化。现在您可以默认使用转义斜杠。我在这里的评论(包括截图)中发布了更多信息:GETting a URL with an url-encoded slash

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