65.9K
CodeProject 正在变化。 阅读更多。
Home

压缩响应和 HTML 空白字符移除器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (24投票s)

2009年7月13日

CPOL

1分钟阅读

viewsIcon

194150

downloadIcon

426

使用 GZipStream 或 DeflateStream 压缩你的 HTML 输出,在可用时将其包含在响应中。 添加了一个新的类 WhiteSpaceFilter,用于移除 HTML 中的空白字符。

压缩

显而易见,我们需要在将响应传递给客户端时对其进行压缩。 压缩的请求和响应总是能提高网站的性能。 如今,几乎 99% 的浏览器都支持 Gzip 或 Deflate 压缩,甚至两者都支持。 因此,如果我们可以检查请求头中是否存在“Accept-Encoding”头,并向客户端返回压缩的响应,那么我们就提高了网站的性能。 请查看下面的代码:

public static void doCompression()
{
     HttpContext context = HttpContext.Current;
     HttpRequest request = context.Request;
     string acceptEncoding = request.Headers["Accept-Encoding"];
     HttpResponse response = context.Response;
     if (!string.IsNullOrEmpty(acceptEncoding))
     {
         acceptEncoding = acceptEncoding.ToUpperInvariant();
         if (acceptEncoding.Contains("GZIP"))
         {
             response.Filter = new GZipStream(context.Response.Filter, 
             CompressionMode.Compress);
             response.AppendHeader("Content-encoding", "gzip");
         }
         else if (acceptEncoding.Contains("DEFLATE"))
         {
             response.Filter = new DeflateStream(context.Response.Filter, 
             CompressionMode.Compress);
             response.AppendHeader("Content-encoding", "deflate");
         }
     }
     response.Cache.VaryByHeaders["Accept-Encoding"] = true;
}

在这里,我们检查请求头是否包含“Accept-Encoding”。 根据它支持的编码,我们使用 GZipStream/ DeflateStream 过滤响应,这些类在 System.IO.Compression 命名空间中可用。 因此,响应将被压缩。 但是,这并不能帮助客户端正确渲染你的页面。 你需要将 Content-Encoding 头添加到响应中,以便客户端能够正确解压缩响应。 我们添加一个 Response 头“Accept-Encoding”,以便请求也使用相同的编码发送数据。

你还可以移除 HTML 中的空白字符来缩小响应。 使用这个类:

public enum CompressOptions
{
    GZip,
    Deflate,
    None
}

public class WhitespaceFilter : Stream
{
    private GZipStream _contentGZip;
    private DeflateStream _content_Deflate;
    private Stream _content;
    private CompressOptions _options;

    public WhitespaceFilter(Stream content, CompressOptions options)
    {
        if (options == CompressOptions.GZip)
        {
            this._contentGZip = new GZipStream(content, CompressionMode.Compress);
            this._content = this._contentGZip;
        }
        else if (options == CompressOptions.Deflate)
        {
            this._content_Deflate = new DeflateStream(content, 
                  CompressionMode.Compress);
            this._content = this._content_Deflate;
        }
        else
        {
            this._content = content;
        }
        this._options = options;
    }


    public override bool CanRead
    {
        get { return this._content.CanRead; }
    }

    public override bool CanSeek
    {
        get { return this._content.CanSeek; }
    }

    public override bool CanWrite
    {
        get { return this._content.CanWrite; }
    }

    public override void Flush()
    {
        this._content.Flush();
    }

    public override long Length
    {
        get { return this._content.Length; }
    }

    public override long Position
    {
        get
        {
            return this._content.Position;
        }
        set
        {
            this._content.Position = value;
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        return this._content.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin)
    {
        return this._content.Seek(offset, origin);
    }

    public override void SetLength(long value)
    {
        this._content.SetLength(value);
    }

    public override void Write(byte[] buffer, int offset, int count)
    {
        byte[] data = new byte[count + 1];
        Buffer.BlockCopy(buffer, offset, data, 0, count);

        string s = System.Text.Encoding.UTF8.GetString(data);
        s = Regex.Replace(s, "^\\s*",string.Empty, RegexOptions.Compiled |
                          RegexOptions.Multiline);
        s = Regex.Replace(s, "\\r\\n", string.Empty, RegexOptions.Compiled | 
                          RegexOptions.Multiline);
        s = Regex.Replace(s, "<!--*.*?-->", string.Empty, RegexOptions.Compiled | 
                          RegexOptions.Multiline); 
        
        byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s);
        this._content.Write(outdata, 0, outdata.GetLength(0));
    }
}

要使用它,只需编写:

internal void Compress()
{
    HttpContext context = HttpContext.Current;
    HttpRequest request = context.Request;
    string acceptEncoding = request.Headers["Accept-Encoding"];
    HttpResponse response = context.Response;
    if (!string.IsNullOrEmpty(acceptEncoding))
    {
        acceptEncoding = acceptEncoding.ToUpperInvariant();
        if (acceptEncoding.Contains("GZIP"))
        {
            //response.Filter = new GZipStream(context.Response.Filter, 
                                //CompressionMode.Compress);
            response.Filter = new WhitespaceFilter(context.Response.Filter, 
                              CompressOptions.GZip);
            response.AppendHeader("Content-encoding", "gzip");
        }
        else if (acceptEncoding.Contains("DEFLATE"))
        {
            //response.Filter = new DeflateStream(context.Response.Filter, 
                                //CompressionMode.Compress);
            response.Filter = new WhitespaceFilter(context.Response.Filter, 
                              CompressOptions.Deflate);
            response.AppendHeader("Content-encoding", "deflate");
        }
    }
    response.Cache.VaryByHeaders["Accept-Encoding"] = true;
}

注意:我使用的正则表达式将移除 HTML 中的额外空格、换行符和注释。 因此,它将减小 HTML 的大小。 另外,在使用它在生产环境中之前,请检查它的工作方式,因为你需要根据你的需要更改正则表达式。

© . All rights reserved.