代码之家  ›  专栏  ›  技术社区  ›  Jesse Hallam

使用响应。筛选器与响应.传输文件

  •  0
  • Jesse Hallam  · 技术社区  · 14 年前

    我在用响应。筛选器为了根据HTTP请求头实现流压缩 Accept-Encoding

    重要的是:

            if (AcceptEncoding.Contains("deflate") || AcceptEncoding == "*")
            {
                 HttpApp.Response.Filter = new DeflateStream(PreviousOutputStream, CompressionMode.Compress);
                 HttpApp.Response.AppendHeader("Content-Encoding", "deflate");
            }
    

    总的来说,这是按计划进行的。但是,我现在使用的是 ActionResult 在MVC控制器上向用户代理提供文件:

            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);
    

    更确切地说,action方法返回 new EmptyResult() Response.TransmitFile() 打电话。如果没有响应。筛选器修改。

    在这种情况下,响应实体到达用户代理时会出现混乱和无法理解的情况。FireFox的Poster插件显示空实体或混乱的实体返回。

    2 回复  |  直到 14 年前
        1
  •  1
  •   Taudris    14 年前

    如果你能帮忙的话,一定要寻找替代品,因为手动压缩ASP.NET不好玩。但是,如果你和我一样头脑冷静,我向你提交以下文件。

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

    现在,请注意:

    • 响应.传输文件()不适用于响应筛选。
    • 响应.BinaryWrite()无法与响应筛选一起工作,因此无法循环文件内容并以这种方式将其写出。
    • 响应.WriteFile()确实可以进行响应筛选,但它会将整个文件加载到内存中,并将其保存在内存中,直到客户端关闭连接为止,这对于大文件来说并不适用。
    • 为了让事情变得有趣一点:如果设置了响应过滤,那么它将停止工作响应.缓冲输出错了。(我只是花了几个小时才弄明白的)

    显然,围绕响应过滤和写入输出流有很多不同的问题。通过使用Reflector和大量的实验,这是迄今为止我发现的最好的解决方案(“就在各种场景下正确工作而言”是最好的):

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

    2. 设置响应.ContentEncoding到BinaryEncoding的一个实例(您可以非常成功地使用singleton模式)。

    3. 使用FileStream打开文件。

    4. 创建 new StreamReader(fileStream, new BinaryEncoding(), false) . “false”参数非常重要,它阻止StreamReader读取字节顺序标记并覆盖二进制编码。

    5. 分配一个char[]的缓冲区(我发现32KB是一个不错的大小)。

    然后,在循环中:

    int n = StreamReader.Read(buffer, 0, buffer.Length);
    Response.Write(buffer, 0, n);
    Response.Flush();
    

    直到n为0。

        2
  •  0
  •   Troy    14 年前

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

    http://technet.microsoft.com/en-us/library/cc771003(WS.10).aspx