尽管以块形式发送数据,但是在发送文件之前,我们知道文件的完整大小,因此我们正确设置了Content-Length标题。这已经在我们的生产环境中工作了一段时间(并且在我们的测试环境中继续使用几乎相同的配置),直到今天。报告的问题是Chrome将尝试打开PDF文件,但会挂起“加载”动画卡住。
因为一切在我们的测试环境中仍然能正常运行,所以我可以使用Firebug来查看在两个环境中回来的响应头。在测试环境中,我正在看到一个适当的“Content-Length”标题,而在生产中已经被Transfer-Encoding:chunked标题替换。 Chrome不喜欢这个,因此挂断了。
我已经阅读了一些文章和帖子,讨论了当没有提供Content-Length头部时,Transfer-Encoding头可以显示,但是我们指定了Content-Length头,并且所有内容仍然运行起来,同时运行相同的代码测试服务器上的相同PDF文件。
测试和生产服务器都运行IIS 7.5,并且都启用了动态和静态压缩。
以下是相关代码:
var fileInfo = new FileInfo(fileToSendDown); Response.ClearHeaders(); Response.ContentType = "application/pdf"; Response.AddHeader("Content-Disposition","filename=test.pdf"); Response.AddHeader("Content-Length",fileInfo.Length.ToString()); var buffer = new byte[1024]; using (var fs = File.Open(file,FileMode.Open,FileAccess.Read,FileShare.Read)) { int read; while ((read = fs.Read(buffer,1024)) > 0) { if (!response.IsClientConnected) break; Response.OutputStream.Write(buffer,read); Response.Flush(); } }
我很幸运地在我的本地工作站上看到了相同的行为,所以使用调试器我已经看到’Transfer-Encoding:chunked’标题被设置在第二遍通过while循环在调用“冲洗” 。在这一点上,响应既具有Content-Length头和Transfer-Encoding头,但是在响应到达浏览器的时候,Firebug只显示Transfer-Encoding头。
UPDATE
我想我已经跟踪了这一点,结合使用“chunks”中的数据发送,并在HttpResponse对象上附加一个“Filter”(我们使用一个过滤器跟踪被发送到每个页面的viewstate的大小) 。在将PDF发送到浏览器时,我们使用HTTP过滤器没有任何意义,因此清除过滤器已经解决了我们的问题。我决定深入挖掘一下,纯粹是出于好奇,并且如果任何人在未来绊倒这个问题,就会更新这个问题。
我在AppHarbor上有一个简单的应用程序,可以复制问题:http://transferencodingtest.apphb.com/.如果您同时检查“使用过滤器”?和“传送块”?你应该可以看到’transfer-encoding:chunked’标题显示(使用Chrome开发工具,Firebug,Fiddler,无论如何)。如果没有选中任何一个框,您将获得适当的内容长度标题。底层代码在github上,所以你可以看到幕后发生了什么:
https://github.com/appakz/TransferEncodingTest
请注意,要在本地进行复制,您需要在IIS 7.5中设置本地网站(7也可以正常工作,我没有尝试过)。 Visual Studio附带的ASP .NET开发服务器不会重现此问题。
我已经在博客帖子中添加了更多的细节:‘Content-Length’ Header Replaced With ‘Transfer-Encoding: Chunked’ in ASP .NET
解决方法
appcmd set config /section:asp /enableChunkedEncoding:False
但是在ASP settings下提到,因此它可能不适用于从ASP.NET处理程序生成的响应。