首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >为什么在手动刷新响应时,ASP.NET会将Content-Length报头替换为Transfer-Encoding报头?

为什么在手动刷新响应时,ASP.NET会将Content-Length报头替换为Transfer-Encoding报头?
EN

Stack Overflow用户
提问于 2011-12-21 06:10:16
回答 3查看 13.3K关注 0票数 17

我们的web应用程序( PDF Forms)有一个页面,该页面将向用户显示最近生成的ASP.NET文件。由于PDF文件有时非常大,我们实现了一种“流”方法,将其分块发送到客户端浏览器。

尽管以块的形式向下发送数据,但在发送之前我们知道文件的完整大小,因此我们适当地设置了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, 0, 1024)) > 0)
    {
        if (!response.IsClientConnected) break;
        Response.OutputStream.Write(buffer, 0, read);
        Response.Flush();
    }
}

我很幸运地在我的本地工作站上看到了相同的行为,所以使用调试器,我已经能够看到在调用“Flush”期间通过while循环的第二次传递中设置了“Transfer-Encoding:chunked”头。此时,响应同时具有Content-Length报头和Transfer-Encoding报头,但不知何故,当响应到达浏览器时,Firebug只显示Transfer-Encoding报头。

更新

我想我已经通过使用“分块”发送数据和将“过滤器”附加到HttpResponse对象(我们使用过滤器来跟踪发送到每个页面的视图状态的大小)的组合来实现这一点。在将PDF发送到浏览器时,我们使用HTTP过滤器是没有意义的,因此清除此处的过滤器已经解决了我们的问题。纯粹出于好奇,我决定深入挖掘一下这个问题,并更新了这个问题,以防其他人在未来遇到这个问题。

我在AppHarbor上有一个简单的应用程序可以重现这个问题:http://transferencodingtest.apphb.com/。如果您同时选中“使用过滤器?”和‘发送块?’你应该可以看到“transfer-encoding:chunked”的标题(使用Chrome开发工具,Firebug,Fiddler等等)。如果没有选中这两个框中的任何一个,您将得到一个正确的content-length标题。底层代码在github上,因此您可以看到幕后发生了什么:

https://github.com/appakz/TransferEncodingTest

请注意,要在本地重现,您需要在IIS 7.5中设置一个本地网站(7也可以,我还没有尝试过)。Visual Studio附带的ASP开发服务器不会重现此问题。

我在这里的博客文章中添加了更多细节:'Content-Length' Header Replaced With 'Transfer-Encoding: Chunked' in ASP .NET

EN

回答 3

Stack Overflow用户

发布于 2011-12-23 02:03:46

an article on MSDN中,你似乎可以禁用分块编码:

appcmd set config /section:asp /enableChunkedEncoding:False

但它是在ASP settings中提到的,所以它可能不适用于从ASP.NET处理程序生成的响应。

票数 5
EN

Stack Overflow用户

发布于 2011-12-23 02:39:00

一旦调用了Response.Flush(),响应主体就会在发送到客户端的过程中出现,因此不能向响应中添加额外的头部。我发现第二个对Response.Flush()的调用不太可能在那个时候添加Transfer-Encoding头。

你说你启用了压缩。这几乎总是需要一个分块的响应。因此,如果服务器在压缩之前知道Content-Length,它可能会用该标头替换Transfer-Encoding标头并分块响应,这是有意义的。但是,即使在服务器上启用了压缩,客户端也必须在其Accept-Encoding请求报头中明确声明对压缩的支持,否则服务器无法压缩响应。你在测试中检查过这一点吗?

最后,由于您是手动调用Response.Flush(),因此请尝试设置Response.Buffer = TrueResponse.BufferOutput = False。显然,它们对Response.Flush()的运营方式产生了相互矛盾的影响。请参阅this pagethis page底部的注释。

票数 4
EN

Stack Overflow用户

发布于 2016-01-07 01:45:35

当我在BufferOutput设置为false的响应流上调用Response.Write时,我在编写大型CSV时遇到了类似的问题(文件不存在,我通过迭代内存中的集合并生成行来逐行写入字符串),但解决方案是更改

Reponse.ContentType = 'text/csv'Reponse.ContentType = 'application/octet-stream'

当内容类型没有设置为应用程序/八位字节流时,添加了一堆其他响应头,比如Content-Encoding - gzip

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8582637

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档