我正在使用Response.Filter,以便根据HTTP请求标头Accept-Encoding
实现流压缩
这是重要的事情:
if (AcceptEncoding.Contains("deflate") || AcceptEncoding == "*")
{
HttpApp.Response.Filter = new DeflateStream(PreviousOutputStream, CompressionMode.Compress);
HttpApp.Response.AppendHeader("Content-Encoding", "deflate");
}
大体上按预期工作。但是,我正在使用MVC控制器上的ActionResult
来向用户代理提供文件:
Response.Clear();
Response.Headers["Content-Type"] = contentType;
Response.Headers["Content-Length"] = contentLength;
if (Request.QueryString["dl"] == "1")
{
Response.Headers["Content-Disposition"] = "attachment; filename=" + fileInfo.Name;
}
Response.Flush();
Response.TransmitFile(fileInfo.FullName);
更确切地说,操作方法在new EmptyResult()
调用后返回Response.TransmitFile()
。如果没有Response.Filter修改,这完全符合预期。
在这种情况下,响应实体到达用户代理是乱码且无法理解的。 FireFox的海报插件显示空实体或混乱的实体回来。
答案 0 :(得分:1)
如果你可以提供帮助,一定要寻找替代方案,因为在ASP.NET中手动进行压缩并不好玩。但是,如果你像我一样头脑冷静,我会向你提交以下内容。
首先:不要使用.NET的内置压缩流类。它们是错误的,可以随机截断流末尾的字节。我一直在使用DotNetZip,效果很好:http://dotnetzip.codeplex.com/
现在,还有一些补充说明:
显然,围绕响应过滤和写入输出流存在很多不同的问题。使用Reflector和大量实验,这是迄今为止我发现的最好的(在各种情况下正确工作的“最佳”)解决方案:
编写一个扩展编码的类,并将其称为BinaryEncoding。实现所有方法,以便正确复制字符和字节,但当然要进行必要的类型转换。
将Response.ContentEncoding设置为BinaryEncoding的实例(您可以非常成功地使用单例模式)。
使用FileStream打开文件。
创建new StreamReader(fileStream, new BinaryEncoding(), false)
。 “false”参数非常重要,它会阻止StreamReader吃掉字节顺序标记并覆盖BinaryEncoding。
分配一个char []的缓冲区(我发现32KB是一个很好的大小)。
然后,循环:
int n = StreamReader.Read(buffer, 0, buffer.Length);
Response.Write(buffer, 0, n);
Response.Flush();
直到n为0.
警告:此方法会导致相当高的CPU使用率。在100兆位LAN上,单个客户端以10MB /秒的速度下载时,一个核心上的CPU使用率约为40-50%。我希望我能找到更好的方法......如果我有Reflector Pro,我可能会找到一个。
答案 1 :(得分:0)
如果您使用的是IIS7或IIS7.5,我建议使用HTTP压缩模块,而不是自己动手。它可能有助于解决问题。
http://technet.microsoft.com/en-us/library/cc771003(WS.10).aspx