繁体   English   中英

将Response.Filter与Response.TransmitFile一起使用

[英]Using Response.Filter with Response.TransmitFile

我使用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);

更确切地说,该动作方法在Response.TransmitFile()调用之后返回new EmptyResult() 无需修改Response.Filter即可完全按预期工作。

在这种情况下,响应实体到达用户代理时出现乱码和难以理解。 FireFox的Poster插件显示了空的实体或混乱的实体回来。

如果可以帮助,一定要寻找替代方法,因为在ASP.NET中手动进行压缩并不有趣。 但是,如果您和我一样头脑坚定,我谨向您提出以下几点。

首先:不要使用.NET的内置压缩流类。 它们有问题,可以随机截断流末尾的字节。 我一直在使用DotNetZip并取得良好的效果: http ://dotnetzip.codeplex.com/

现在,一些附加说明:

  • Response.TransmitFile()不适用于响应过滤。
  • Response.BinaryWrite()不适用于响应过滤,因此您无法循环遍历文件的内容并将其写出。
  • Response.OutputStream不能与响应筛选一起使用,因此,您也无法遍历文件的内容并以这种方式将其写出。
  • Response.WriteFile()确实可以与响应筛选一起使用,但是它将整个文件加载到内存中并保存在那里,直到客户端关闭连接为止,这不适用于大型文件。
  • 为了使事情变得更加有趣:如果将Response.BufferOutput设置为false,则响应过滤将停止工作。 (我只是花了几个小时才弄清楚这一点)

显然,围绕响应过滤和写入输出流存在很多不同的问题。 通过使用Reflector和大量实验,这是到目前为止我发现的最佳解决方案(“在各种情况下都能正常工作”)。

  1. 写一个扩展Encoding的类,并将其称为BinaryEncoding。 实现所有方法,以便它们正确复制字符和字节,但是当然要进行必要的类型转换。

  2. 将Response.ContentEncoding设置为BinaryEncoding的实例(您可以非常成功地使用单例模式)。

  3. 使用FileStream打开文件。

  4. 创建一个new StreamReader(fileStream, new BinaryEncoding(), false) 该“ false”参数非常重要,它可以阻止StreamReader吃字节顺序标记并覆盖您的BinaryEncoding。

  5. 分配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,也许可以找到一个。

如果您使用的是IIS7或IIS7.5,我建议您使用HTTP压缩模块,而不要自己动手使用。 这可能有助于解决问题。

http://technet.microsoft.com/zh-cn/library/cc771003(WS.10).aspx

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM