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] 标注  即可。

 

你可能感兴趣的:(Data)