ASP.NET HttpModule:防止分块传输编码

时间:2016-01-26 09:30:25

标签: c# asp.net iis httpmodule chunked-encoding

我正在研究一个自己的HTTP(gzip)压缩的HttpModule。问题是,只要我将Content-Encoding响应标头设置为任何“可压缩”值(如gzipdeflate等)并在流中返回压缩响应,IIS就会切换Transfer-Encodingchunked并且响应没有真正得到压缩(在Chrome和IE开发工具中都经过测试)。

我还明确地将Content-Length设置为压缩字节数组的长度,但它不会显示在客户端的实际HTTP响应中。

如果我将Transfer-Encoding设置为identity或者根本没有指定它并将未压缩的字节推送到输出流,则响应会正常发送,而不会出现分块。

我已将HttpModule简化为以下示例。它会记录Compressed 123 bytes to 110消息,但Chrome会将实际响应记录为271字节。

如何防止此行为?我尝试在Content-Length中明确设置HttpContext.Current.Response(在某处可以提供帮助),但它也无济于事。

public class SimpleTestHttpModule : IHttpModule
{
    public void Init (HttpApplication context)
    {
        context.BeginRequest += Application_BeginRequest;
    }

    public void Dispose()
    {
    }

    private static void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpContext httpContext = application.Context;

        string text = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
        byte[] uncompressedBytes = new UTF8Encoding (false).GetBytes (text);

        httpContext.Response.ContentType = "text/plain";

        GZipCompressAndWrite(httpContext, uncompressedBytes);

        httpContext.Response.End();
    }

    private static void GZipCompressAndWrite (HttpContext context, byte[] bytes)
    {
        context.Response.AddHeader ("Content-Encoding", "gzip");

        byte[] compressed = GZipCompressByteArray (bytes);
        log.DebugFormat ("Compressed {0} bytes to {1}", bytes.Length, compressed.Length);

        string contentLenStr = compressed.Length.ToString (CultureInfo.InvariantCulture);
        HttpContext.Current.Response.Headers["Content-Length"] = contentLenStr;
        context.Response.Headers["Content-Length"] = contentLenStr;
        context.Response.BinaryWrite (compressed);
    }

    private static byte[] GZipCompressByteArray (byte[] data)
    {
        using (MemoryStream outputStream = new MemoryStream ())
        {
            using (GZipStream compressStream = new GZipStream(outputStream, CompressionMode.Compress, false))
                compressStream.Write (data, 0, data.Length);

            outputStream.Flush();
            return outputStream.ToArray ();
        }
    }

    private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
}

0 个答案:

没有答案