【发布时间】:2015-05-06 18:25:32
【问题描述】:
我正在开发一个小型 C#/WPF 应用程序,该应用程序使用手工制作的 HttpWebRequest 调用和 JSON 序列化与在 Ruby on Rails 中实现的 Web 服务接口。如果没有缓存,一切都可以正常工作,而且我还可以进行 HTTP 身份验证和压缩。
一旦我通过设置request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.CacheIfAvailable); 启用缓存,事情就会出错 - 在生产环境中。当连接到一个简单的 WEBrick 实例时,一切正常,我得到了HTTP/1.1 304 Not Modified,正如预期的那样,HttpWebRequest 提供了缓存的内容。
当我对生产服务器尝试相同的操作时,运行 nginx/0.8.53 + Phusion Passenger 3.0.0,应用程序中断。第一个请求(未缓存)得到了正确处理,但是在导致 304 响应的第二个请求中,我收到了一个 WebException 声明“请求被中止:请求被取消。”当我调用request.GetResponse()。
我已经通过fiddler 建立了连接,但这并没有太大帮助; WEBrick 和 nginx 都返回一个空的实体主体,尽管响应头不同。拦截请求并更改 nginx 的响应标头以匹配 WEBrick 并没有改变任何东西,这让我认为这可能是一个保持活动的问题;但是,设置request.KeepAlive = false; 不会改变任何东西 - 它在连接到 WEBrick 时不会破坏东西,并且在连接到 nginx 时不会修复东西。
对于它的价值,WebException.InnerException 是一个NullReferenceException 与以下StackTrace:
at System.Net.HttpWebRequest.CheckCacheUpdateOnResponse()
at System.Net.HttpWebRequest.CheckResubmitForCache(Exception& e)
at System.Net.HttpWebRequest.DoSubmitRequestProcessing(Exception& exception)
at System.Net.HttpWebRequest.ProcessResponse()
at System.Net.HttpWebRequest.SetResponse(CoreResponseData coreResponseData)
(工作的)WEBrick 连接的标头:
########## request
GET /users/current.json HTTP/1.1
Authorization: Basic *REDACTED*
Content-Type: application/json
Accept: application/json
Accept-Charset: utf-8
Host: testbox.local:3030
If-None-Match: "84a49062768e4ca619b1c081736da20f"
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
########## response
HTTP/1.1 304 Not Modified
X-Ua-Compatible: IE=Edge
Etag: "84a49062768e4ca619b1c081736da20f"
Date: Wed, 01 Dec 2010 18:18:59 GMT
Server: WEBrick/1.3.1 (Ruby/1.8.7/2010-08-16)
X-Runtime: 0.177545
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: *REDACTED*
(抛出异常的)nginx 连接的标头:
########## request
GET /users/current.json HTTP/1.1
Authorization: Basic *REDACTED*
Content-Type: application/json
Accept: application/json
Accept-Charset: utf-8
Host: testsystem.local:8080
If-None-Match: "a64560553465e0270cc0a23cc4c33f9f"
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
########## response
HTTP/1.1 304 Not Modified
Connection: keep-alive
Status: 304
X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 3.0.0
ETag: "a64560553465e0270cc0a23cc4c33f9f"
X-UA-Compatible: IE=Edge,chrome=1
X-Runtime: 0.240160
Set-Cookie: *REDACTED*
Cache-Control: max-age=0, private, must-revalidate
Server: nginx/0.8.53 + Phusion Passenger 3.0.0 (mod_rails/mod_rack)
更新:
我尝试做一个快速而肮脏的手动 ETag 缓存,但结果证明这是不行的:我在调用 request.GetResponce() 时得到一个 WebException,告诉我 “远程服务器返回一个错误:(304)未修改。” - 是的,.NET,我有点知道,我想(尝试)自己处理它,grr。
更新 2:
更接近问题的根源。 showstopper 似乎是 initial 请求的响应标头中的差异。 WEBrick 包含一个 Date: Wed, 01 Dec 2010 21:30:01 GMT 标头,该标头不存在于 nginx 回复中。还有其他区别,但是用 fiddler 拦截初始 nginx 回复并添加Date 标头,随后的HttpWebRequests 能够处理(未修改的)nginx 304 回复。
打算尝试寻找解决方法,以及让 nginx 添加 Date 标头。
更新 3:
似乎服务器端问题与 Phusion Passenger 相关,他们有一个 open issue 关于缺少 Date 标头。我仍然会说HttpWebRequest 的行为是......次优。
更新 4:
为该错误添加了Microsoft Connect 票证。
【问题讨论】:
-
嗨!我认为您在 HttpWebRequest 中发现了一个错误。你能创建一个重现日志(参见ferozedaud.blogspot.com/2009/08/tracing-with-systemnet.html)并在connect 上创建一个错误请求吗?这样,微软就可以解决这个问题。
-
@feroze:我昨天没时间了,但我现在已经在 Connect 上添加了 bug 票。
标签: c# httpwebrequest