首页 > 代码库 > 在MVC 中对返回的 data 进行压缩

在MVC 中对返回的 data 进行压缩

在webAPI 中返回数据,在数据量比较大的情况的下,返回的data 也可能比较大,有时候可能大于1兆,因此对数据进行压缩能极大的提高数据下载到客户端的时间,提高页面的加载速度。

思路: 在web api 中添加 action filter attribute 来实现,我们先看下其定义:

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]  public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IFilter  {    /// <summary>    /// Occurs before the action method is invoked.    /// </summary>    /// <param name="actionContext">The action context.</param>    public virtual void OnActionExecuting(HttpActionContext actionContext);    /// <summary>    /// Occurs after the action method is invoked.    /// </summary>    /// <param name="actionExecutedContext">The action executed context.</param>    public virtual void OnActionExecuted(HttpActionExecutedContext actionExecutedContext);    /// <summary>    /// Executes the filter action asynchronously.    /// </summary>    ///     /// <returns>    /// The newly created task for this operation.    /// </returns>    /// <param name="actionContext">The action context.</param><param name="cancellationToken">The cancellation token assigned for this task.</param><param name="continuation">The delegate function to continue after the action method is invoked.</param>    Task<HttpResponseMessage> IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation);  }

代码很清晰,关键是两个虚方法 OnActionExecuting(在controller 调用 action方法之前执行),OnActionExecuted( 在controller 调用 action方法之后执行)。

因为我们要对action 执行后的json 进行压缩,所以我们只需要重写OnActionExecuted 方法即可。

在工程中添加一个类CompressResponseAttribute.cs,

具体实现代码如下:

    public class CompressResponseAttribute : ActionFilterAttribute    {        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)        {            var request = actionExecutedContext.Request;            var response = actionExecutedContext.Response;            var contentBytes = response.Content.ReadAsByteArrayAsync().Result;            byte[] compressedBytes;            string contentEncoding = string.Empty;            using (var output = new MemoryStream())            {                if (request.Headers.AcceptEncoding.Any(v => v.Value.Equals("gzip", StringComparison.OrdinalIgnoreCase)))                {                    contentEncoding = "gzip";                    using (var gZipStream = new GZipStream(output, CompressionMode.Compress))                    {                        gZipStream.Write(contentBytes, 0, contentBytes.Length);                    }                }                else if (request.Headers.AcceptEncoding.Any(v => v.Value.Equals("deflate", StringComparison.OrdinalIgnoreCase)))                {                    contentEncoding = "deflate";                    using (var deflateStream = new DeflateStream(output, CompressionMode.Compress))                    {                        deflateStream.Write(contentBytes, 0, contentBytes.Length);                    }                }                compressedBytes = output.ToArray();            }                                if (!string.IsNullOrEmpty(contentEncoding))            {                var originalContentType = response.Content.Headers.ContentType.ToString();                response.Content = new System.Net.Http.ByteArrayContent(compressedBytes);                response.Content.Headers.Remove("Content-Type");                response.Content.Headers.Add("Content-encoding", contentEncoding);                response.Content.Headers.Add("Content-Type", originalContentType);            }            base.OnActionExecuted(actionExecutedContext);        }    }

上面的代码实现的压缩方式优先为gzip。

最后,在需要压缩返回的method 上面添加 [CompressResponse] 标注  即可。

 

在MVC 中对返回的 data 进行压缩