zoukankan      html  css  js  c++  java
  • 【转】HttpCompress


    在PreRequestHandlerExecute 事件里边用DeflateStream修饰的Response.Filter替代Response.Filter
      public sealed class CompressionModule : IHttpModule
      {

        #region IHttpModule Members

        /// <summary>
        /// Disposes of the resources (other than memory) used by the module
        /// that implements <see cref="T:System.Web.IHttpModule"></see>.
        /// </summary>
        void IHttpModule.Dispose()
        {
          // Nothing to dispose;
        }

        /// <summary>
        /// Initializes a module and prepares it to handle requests.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpApplication"></see>
        /// that provides access to the methods, properties, and events common to
        /// all application objects within an ASP.NET application.
        /// </param>
        void IHttpModule.Init(HttpApplication context)
        {
          if (BlogSettings.Instance.EnableHttpCompression)
          {
            context.PreRequestHandlerExecute += new EventHandler(context_PostReleaseRequestState);
          }
        }

        #endregion

        private const string GZIP = "gzip";
        private const string DEFLATE = "deflate";

        #region Compress page

        /// <summary>
        /// Handles the BeginRequest event of the context control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void context_PostReleaseRequestState(object sender, EventArgs e)
        {
          HttpApplication app = (HttpApplication)sender;
          if (app.Context.CurrentHandler is System.Web.UI.Page && app.Request["HTTP_X_MICROSOFTAJAX"] == null)
          {
            if (IsEncodingAccepted(DEFLATE))
            {
              app.Response.Filter = new DeflateStream(app.Response.Filter, CompressionMode.Compress);
              SetEncoding(DEFLATE);
            }
            else if (IsEncodingAccepted(GZIP))
            {
              app.Response.Filter = new GZipStream(app.Response.Filter, CompressionMode.Compress);
              SetEncoding(GZIP);
            }
          }
                else if (app.Context.Request.Path.Contains("WebResource.axd"))
                {
                    app.Context.Response.Cache.SetExpires(DateTime.Now.AddDays(30));
                }
        }

        /// <summary>
        /// Checks the request headers to see if the specified
        /// encoding is accepted by the client.
        /// </summary>
        private static bool IsEncodingAccepted(string encoding)
        {
          HttpContext context = HttpContext.Current;
          return context.Request.Headers["Accept-encoding"] != null && context.Request.Headers["Accept-encoding"].Contains(encoding);
        }   

        /// <summary>
        /// Adds the specified encoding to the response headers.
        /// </summary>
        /// <param name="encoding"></param>
        private static void SetEncoding(string encoding)
        {
          HttpContext.Current.Response.AppendHeader("Content-encoding", encoding);
        }

        #endregion

      }

    二:
    HttpCompress是在.NET内部通过httpModules模型来实现自定义的压缩模块。

    1. 配置
    <httpModules>
          <add name="CompressionModule" type="blowery.Web.HttpCompress.HttpModule, blowery.web.HttpCompress"/>
    </httpModules> 

    2.注册事件钩子
    context.ReleaseRequestState += new EventHandler(this.CompressContent);
    context.PreSendRequestHeaders += new EventHandler(this.CompressContent);
    IHttpModule事件

    3.在代码发送前压缩

    void CompressContent(object sender, EventArgs e) {
    HttpApplication app 
    = (HttpApplication)sender;
          
    if(!app.Context.Items.Contains(INSTALLED_KEY)) {
    //设置标志避免重复压缩
            app.Context.Items.Add(INSTALLED_KEY, INSTALLED_TAG);

    //设置缓存敏感参数
           app.Response.Cache.VaryByHeaders["Accept-Encoding"= true;

    //根据Accept-Encoding寻找合适的压缩过滤模块CompressingFilter : HttpOutputFilter;
    //如果没有设置Accept-Encoding,或者寻找失败均是直接返回,即不压缩
    ...
    CompressingFilter filter 
    = GetFilterForScheme(types, app.Response.Filter, settings);
            
    if(filter == null){
              
    // if we didn't find a filter, bail out
              return;
            }

            app.Response.Filter 
    = filter;
    }

    }

    4.压缩类实现

    HttpOutputFilter ,不支持Read, Seek,GetLength等操作,与之相关控制属性返回false, 具体方法或属性则抛异常new NotSupportedException(); 

    using System;
    using System.IO;

    namespace blowery.Web.HttpCompress {
      
    /// <summary>
      
    /// The base of anything you want to latch onto the Filter property of a <see cref="System.Web.HttpResponse"/>
      
    /// object.
      
    /// </summary>
      
    /// <remarks>
      
    /// <p></p>These are generally used with <see cref="HttpModule"/> but you could really use them in
      
    /// other HttpModules.  This is a general, write-only stream that writes to some underlying stream.  When implementing
      
    /// a real class, you have to override void Write(byte[], int offset, int count).  Your work will be performed there.
      
    /// </remarks>

      public abstract class HttpOutputFilter : Stream {
        
        
    private Stream _sink;

        
    /// <summary>
        
    /// Subclasses need to call this on contruction to setup the underlying stream
        
    /// </summary>
        
    /// <param name="baseStream">The stream we're wrapping up in a filter</param>

        protected HttpOutputFilter(Stream baseStream) 
          _sink 
    = baseStream;
        }


        
    /// <summary>
        
    /// Allow subclasses access to the underlying stream
        
    /// </summary>

        protected Stream BaseStream {
          
    getreturn _sink; }
        }


        
    /// <summary>
        
    /// False.  These are write-only streams
        
    /// </summary>

        public override bool CanRead {
          
    get return false; }
        }


        
    /// <summary>
        
    /// False.  These are write-only streams
        
    /// </summary>

        public override bool CanSeek {
          
    get return false; }
        }


        
    /// <summary>
        
    /// True.  You can write to the stream.  May change if you call Close or Dispose
        
    /// </summary>

        public override bool CanWrite {
          
    get return _sink.CanWrite; }
        }


        
    /// <summary>
        
    /// Not supported.  Throws an exception saying so.
        
    /// </summary>
        
    /// <exception cref="NotSupportedException">Thrown.  Always.</exception>

        public override long Length {
          
    get throw new NotSupportedException(); }
        }


        
    /// <summary>
        
    /// Not supported.  Throws an exception saying so.
        
    /// </summary>
        
    /// <exception cref="NotSupportedException">Thrown.  Always.</exception>

        public override long Position {
          
    get throw new NotSupportedException(); }
          
    set throw new NotSupportedException(); }
        }


        
    /// <summary>
        
    /// Not supported.  Throws an exception saying so.
        
    /// </summary>
        
    /// <exception cref="NotSupportedException">Thrown.  Always.</exception>

        public override long Seek(long offset, System.IO.SeekOrigin direction) {
          
    throw new NotSupportedException();
        }


        
    /// <summary>
        
    /// Not supported.  Throws an exception saying so.
        
    /// </summary>
        
    /// <exception cref="NotSupportedException">Thrown.  Always.</exception>

        public override void SetLength(long length) {
          
    throw new NotSupportedException();
        }

        
        
    /// <summary>
        
    /// Closes this Filter and the underlying stream.
        
    /// </summary>
        
    /// <remarks>
        
    /// If you override, call up to this method in your implementation.
        
    /// </remarks>

        public override void Close() {
          _sink.Close();
        }


        
    /// <summary>
        
    /// Fluses this Filter and the underlying stream.
        
    /// </summary>
        
    /// <remarks>
        
    /// If you override, call up to this method in your implementation.
        
    /// </remarks>

        public override void Flush() {
          _sink.Flush();
        }


        
    /// <summary>
        
    /// Not supported.
        
    /// </summary>
        
    /// <param name="buffer">The buffer to write into.</param>
        
    /// <param name="offset">The offset on the buffer to write into</param>
        
    /// <param name="count">The number of bytes to write.  Must be less than buffer.Length</param>
        
    /// <returns>An int telling you how many bytes were written</returns>

        public override int Read(byte[] buffer, int offset, int count) {
          
    throw new NotSupportedException();
        }


      }

    }

    CompressingFilter 增加了压缩相关的属性和方法,如,写头

    using System;
    using System.IO;
    using System.Web;

    namespace blowery.Web.HttpCompress {
      
    /// <summary>
      
    /// Base for any HttpFilter that performing compression
      
    /// </summary>
      
    /// <remarks>
      
    /// When implementing this class, you need to implement a <see cref="HttpOutputFilter"/>
      
    /// along with a <see cref="CompressingFilter.ContentEncoding"/>.  The latter corresponds to a 
      
    /// content coding (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
      
    /// that your implementation will support.
      
    /// </remarks>

      public abstract class CompressingFilter : HttpOutputFilter {

        
    private bool hasWrittenHeaders = false;

        
    /// <summary>
        
    /// Protected constructor that sets up the underlying stream we're compressing into
        
    /// </summary>
        
    /// <param name="baseStream">The stream we're wrapping up</param>
        
    /// <param name="compressionLevel">The level of compression to use when compressing the content</param>

        protected CompressingFilter(Stream baseStream, CompressionLevels compressionLevel) : base(baseStream) {
          _compressionLevel 
    = compressionLevel;
        }


        
    /// <summary>
        
    /// The name of the content-encoding that's being implemented
        
    /// </summary>
        
    /// <remarks>
        
    /// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5 for more
        
    /// details on content codings.
        
    /// </remarks>

        public abstract string ContentEncoding get; }

        
    private CompressionLevels _compressionLevel;

        
    /// <summary>
        
    /// Allow inheriting classes to get access the the level of compression that should be used
        
    /// </summary>

        protected CompressionLevels CompressionLevel {
          
    get return _compressionLevel; }
        }


        
    /// <summary>
        
    /// Keeps track of whether or not we're written the compression headers
        
    /// </summary>

        protected bool HasWrittenHeaders 
          
    get return hasWrittenHeaders; } 
        }


        
    /// <summary>
        
    /// Writes out the compression-related headers.  Subclasses should call this once before writing to the output stream.
        
    /// </summary>

        protected void WriteHeaders() {
          
    // this is dangerous.  if Response.End is called before the filter is used, directly or indirectly,
          
    // the content will not pass through the filter.  However, this header will still be appended.  
          
    // Look for handling cases in PreRequestSendHeaders and Pre
          HttpContext.Current.Response.AppendHeader("Content-Encoding"this.ContentEncoding);
          
    //HttpContext.Current.Response.AppendHeader("X-Compressed-By", "HttpCompress");
          hasWrittenHeaders = true;
        }



      }

    }

    执行类,利用压缩类实现了Write,Close,Flush

    using System;
    using System.IO;

    using System.IO.Compression;

    namespace blowery.Web.HttpCompress {
      
    /// <summary>
      
    /// Summary description for DeflateFilter.
      
    /// </summary>

      public class DeflateFilter : CompressingFilter {

        
    /// <summary>
        
    /// compression stream member
        
    /// has to be a member as we can only have one instance of the
        
    /// actual filter class
        
    /// </summary>

        private DeflateStream m_stream = null;

        
    /// <summary>
        
    /// Basic constructor that uses the Normal compression level
        
    /// </summary>
        
    /// <param name="baseStream">The stream to wrap up with the deflate algorithm</param>

        public DeflateFilter(Stream baseStream) : this(baseStream, CompressionLevels.Normal) { }

        
    /// <summary>
        
    /// Full constructor that allows you to set the wrapped stream and the level of compression
        
    /// </summary>
        
    /// <param name="baseStream">The stream to wrap up with the deflate algorithm</param>
        
    /// <param name="compressionLevel">The level of compression to use</param>

        public DeflateFilter(Stream baseStream, CompressionLevels compressionLevel) : base(baseStream, compressionLevel) {
            m_stream 
    = new DeflateStream(baseStream, CompressionMode.Compress);
        }


        
    /// <summary>
        
    /// Write out bytes to the underlying stream after compressing them using deflate
        
    /// </summary>
        
    /// <param name="buffer">The array of bytes to write</param>
        
    /// <param name="offset">The offset into the supplied buffer to start</param>
        
    /// <param name="count">The number of bytes to write</param>

        public override void Write(byte[] buffer, int offset, int count) {
          
    if(!HasWrittenHeaders) WriteHeaders();
          m_stream.Write(buffer, offset, count);
        }


        
    /// <summary>
        
    /// Return the Http name for this encoding.  Here, deflate.
        
    /// </summary>

        public override string ContentEncoding {
          
    get return "deflate"; }
        }


        
    /// <summary>
        
    /// Closes this Filter and calls the base class implementation.
        
    /// </summary>

        public override void Close() {
          m_stream.Close();
        }


        
    /// <summary>
        
    /// Flushes that the filter out to underlying storage
        
    /// </summary>

        public override void Flush() {
          m_stream.Flush();
        }

      }

    }

  • 相关阅读:
    EOF:getchar()函数返回的一个特殊值
    elementUI的el-select使用filterable无效
    element table单元格相关的样式
    关于前端权限的一点想法--续
    IE浏览器与PDF文件
    vue form表单数据无法修改
    computed数据变动,table加载不全
    vue插件开发(本地使用)
    element table
    对象删除(消耗时间验证)
  • 原文地址:https://www.cnblogs.com/shikyoh/p/2013502.html
Copyright © 2011-2022 走看看