我正在研究一个自己的HTTP(gzip)压缩的HttpModule。问题是,只要我将Content-Encoding
响应标头设置为任何“可压缩”值(如gzip
,deflate
等)并在流中返回压缩响应,IIS就会切换Transfer-Encoding
到chunked
并且响应没有真正得到压缩(在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);
}