WebAPI性能优化之压缩解压

有时候为了提升WebAPI的性能,减少响应时间,我们会使用压缩和解压,而现在大多数客户端浏览器都提供了内置的解压支持。在WebAPI请求的资源越大时,使用压缩对性能提升的效果越明显,而当请求的资源很小时则不需要使用压缩和解压,因为压缩和解压同样也是需要耗费一定的时间的。

看见老外写了一篇ASP.NET Web API GZip compression ActionFilter with 8 lines of code

说实话被这标题吸引了,8行代码实现GZip压缩过滤器,我就照着他的去实践了一番,发现居然中文出现乱码。

按照他的实现方式:

1、下载DotNetZipLib

2、解压后添加Ionic.Zlib.dll的dll引用

3、新建DeflateCompression特性和GZipCompression特性,分别代表Deflate压缩和GZip压缩,这两种压缩方式的实现代码很相似

不同的地方就是

actContext.Response.Content.Headers.Add("Content-encoding", "gzip");

actContext.Response.Content.Headers.Add("Content-encoding", "deflate");

  var compressor = new DeflateStream(
                    output, CompressionMode.Compress,
                    CompressionLevel.BestSpeed)
 var compressor = new GZipStream(
                    output, CompressionMode.Compress,
                    CompressionLevel.BestSpeed)

using System.Net.Http;
using System.Web.Http.Filters;

namespace WebAPI.Filter
{
    public class GZipCompressionAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actContext)
        {
            var content = actContext.Response.Content;
            var bytes = content == null ? null : content.ReadAsByteArrayAsync().Result;
            var zlibbedContent = bytes == null ? new byte[0] :
            CompressionHelper.GZipByte(bytes);
            actContext.Response.Content = new ByteArrayContent(zlibbedContent);
            actContext.Response.Content.Headers.Remove("Content-Type");
            actContext.Response.Content.Headers.Add("Content-encoding", "gzip");
            actContext.Response.Content.Headers.Add("Content-Type", "application/json");
            base.OnActionExecuted(actContext);
        }
    }
}
using System.Net.Http;
using System.Web.Http.Filters;

namespace WebAPI.Filter
{
    public class DeflateCompressionAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actContext)
        {
            var content = actContext.Response.Content;
            var bytes = content == null ? null : content.ReadAsByteArrayAsync().Result;
            var zlibbedContent = bytes == null ? new byte[0] :
            CompressionHelper.DeflateByte(bytes);
            actContext.Response.Content = new ByteArrayContent(zlibbedContent);
            actContext.Response.Content.Headers.Remove("Content-Type");
            actContext.Response.Content.Headers.Add("Content-encoding", "deflate");
            actContext.Response.Content.Headers.Add("Content-Type", "application/json");
            base.OnActionExecuted(actContext);
        }
    }

4、添加一个压缩帮助类CompressionHelper

using System.IO;
using Ionic.Zlib;

namespace WebAPI.Filter
{
    public class CompressionHelper
    {
        public static byte[] DeflateByte(byte[] str)
        {
            if (str == null)
            {
                return null;
            }

            using (var output = new MemoryStream())
            {
                using (
                    var compressor = new DeflateStream(
                    output, CompressionMode.Compress,
                    CompressionLevel.BestSpeed))
                {
                    compressor.Write(str, 0, str.Length);
                }

                return output.ToArray();
            }
        }
        public static byte[] GZipByte(byte[] str)
        {
            if (str == null)
            {
                return null;
            }
            using (var output = new MemoryStream())
            {
                using (
                    var compressor = new GZipStream(
                    output, CompressionMode.Compress,
                    CompressionLevel.BestSpeed))
                {
                    compressor.Write(str, 0, str.Length);
                }

                return output.ToArray();
            }
        }
    }
}

5、控制器调用,这里我写的测试代码:

    public class TestController : ApiController
    {
        StringBuilder sb = new StringBuilder();

        [GZipCompression]
        public string Get(int id)
        {
            for (int i = 0; i < 1000;i++ )
            {
                sb.Append("这里是中国的领土" + i);
            }
            return sb.ToString() + DateTime.Now.ToLocalTime() + "," + id;
        }
    }

先看下不使用压缩,注释//[GZipCompression] 标记,文件大小是26.4kb,请求时间是1.27s

使用[GZipCompression]标记,添加压缩后,文件大小是2.4kb,响应时间是1.21,Respouse Body明显小了很多,但是响应时间少得并不明显,因为在本地环境下载太快了,而压缩解压却要消耗一定的时间,界面加载的时间主要消耗在onload上了。有个问题:中文显示乱码了。

使用.net自带的压缩,在System.IO.Compression中提供了对应的类库——GZipStream与DeflateStream。控制器调用代码不变,新建一个CompressContentAttribute.cs类,代码如下:

using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace WebAPI.Filter
{
    // <summary>
    /// 自动识别客户端是否支持压缩,如果支持则返回压缩后的数据
    /// Attribute that can be added to controller methods to force content
    /// to be GZip encoded if the client supports it
    /// </summary>
    public class CompressContentAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// Override to compress the content that is generated by
        /// an action method.
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            GZipEncodePage();
        }

        /// <summary>
        /// Determines if GZip is supported
        /// </summary>
        /// <returns></returns>
        public static bool IsGZipSupported()
        {
            string AcceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"];
            if (!string.IsNullOrEmpty(AcceptEncoding) &&
                    (AcceptEncoding.Contains("gzip") || AcceptEncoding.Contains("deflate")))
                return true;
            return false;
        }

        /// <summary>
        /// Sets up the current page or handler to use GZip through a Response.Filter
        /// IMPORTANT:
        /// You have to call this method before any output is generated!
        /// </summary>
        public static void GZipEncodePage()
        {
            HttpResponse Response = HttpContext.Current.Response;

            if (IsGZipSupported())
            {
                string AcceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"];

                if (AcceptEncoding.Contains("deflate"))
                {
                    Response.Filter = new System.IO.Compression.DeflateStream(Response.Filter,
                                               System.IO.Compression.CompressionMode.Compress);
                    #region II6不支持此方法,(实际上此值默认为null 也不需要移除)
                    //Response.Headers.Remove("Content-Encoding");
                    #endregion
                    Response.AppendHeader("Content-Encoding", "deflate");
                }
                else
                {
                    Response.Filter = new System.IO.Compression.GZipStream(Response.Filter,
                                                 System.IO.Compression.CompressionMode.Compress);
                    #region II6不支持此方法,(实际上此值默认为null 也不需要移除)
                    //Response.Headers.Remove("Content-Encoding");
                    #endregion
                    Response.AppendHeader("Content-Encoding", "gzip");
                }
            }

            // Allow proxy servers to cache encoded and unencoded versions separately
            Response.AppendHeader("Vary", "Content-Encoding");
        }
    }

    /// <summary>
    /// 强制Defalte压缩
    /// Content-encoding:gzip,Content-Type:application/json
    /// DEFLATE是一个无专利的压缩算法,它可以实现无损数据压缩,有众多开源的实现算法。
    /// </summary>
    public class DeflateCompressionAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            HttpResponse Response = HttpContext.Current.Response;
            Response.Filter = new System.IO.Compression.DeflateStream(Response.Filter,
                                              System.IO.Compression.CompressionMode.Compress);
            #region II6不支持此方法,(实际上此值默认为null 也不需要移除)
            //Response.Headers.Remove("Content-Encoding");
            #endregion
            Response.AppendHeader("Content-Encoding", "deflate");
        }
    }

    /// <summary>
    /// 强制GZip压缩,application/json
    /// Content-encoding:gzip,Content-Type:application/json
    /// GZIP是使用DEFLATE进行压缩数据的另一个压缩库
    /// </summary>
    public class GZipCompressionAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext filterContext)
        {
            HttpResponse Response = HttpContext.Current.Response;
            Response.Filter = new System.IO.Compression.GZipStream(Response.Filter,
                                              System.IO.Compression.CompressionMode.Compress);
            #region II6不支持此方法,(实际上此值默认为null 也不需要移除)
            //Response.Headers.Remove("Content-Encoding");
            #endregion
            Response.AppendHeader("Content-Encoding", "gzip");
        }
    }
}

运行查看结果,压缩能力比DotNetZipLib略差,但是不再出现乱码了。

把控制器代码中的标记改为   [DeflateCompression],使用Deflate压缩再来看下效果:

Deflate压缩后,Content-Length值为2538,而GZip压缩Content-Length值为2556,可见Deflate压缩效果更好。

这里,WebAPI的压缩我都是通过Action过滤器的方式来实现,当然你也可以写在WebAPI中的全局配置中,考虑到有些API接口并不需要使用到压缩,所以就通过Action过滤器的方式来实现了。

dudu的这篇文章HttpClient与APS.NET Web API:请求内容的压缩与解压在客户端压缩、在服务端解压。

原文地址:https://www.cnblogs.com/lhxsoft/p/8663637.html

时间: 2024-10-10 11:11:45

WebAPI性能优化之压缩解压的相关文章

WebAPI性能优化

WebAPI性能优化之压缩解压 有时候为了提升WebAPI的性能,减少响应时间,我们会使用压缩和解压,而现在大多数客户端浏览器都提供了内置的解压支持.在WebAPI请求的资源越大时,使用压缩对性能提升的效果越明显,而当请求的资源很小时则不需要使用压缩和解压,因为压缩和解压同样也是需要耗费一定的时间的. 看见老外写了一篇ASP.NET Web API GZip compression ActionFilter with 8 lines of code 说实话被这标题吸引了,8行代码实现GZip压缩

基于哈夫曼编码的压缩解压程序

这个程序是研一上学期的课程大作业.当时,跨专业的我只有一点 C 语言和数据结构基础,为此,我查阅了不少资料,再加上自己的思考和分析,实现后不断调试.测试和完善,耗时一周左右,在 2012/11/19 完成.虽然这是一个很小的程序,但却是我完成的第一个程序. 源码托管在 Github:点此打开链接 一.问题描述: 名称:基于哈夫曼编码的文件压缩解压 目的:利用哈夫曼编码压缩存储文件,节省空间 输入:任何格式的文件(压缩)或压缩文件(解压) 输出:压缩文件或解压后的原文件 功能:利用哈夫曼编码压缩解

Lniux常见的压缩/解压命令小结

转载请注明: 导航制导与控制实验室 2014年12月16日 在linux开发过程中,经常会遇资料的打包/解包.压缩/解压:本文我将在linux系统中常用的命令进行了整理和分类,内容如下: 1.tar 命令,主要是对Dir先归档,在借助其他命令处理归档文件: 2.单个文件的压缩命令,对单个文件进行处理的命令,有时也可以借助tar命令对目录先打包,再进行压缩: 3.zip.rar压缩命令,即可对单个文件也可对目录进行压缩处理,该方法利于不同操作系统的处理: 该文章只是作者本人的理解,有些命令还会验证

压缩&amp;&amp;解压命令汇总

以下是搜集的Linux系统下,压缩&&解压命令,以备参考使用. .tar 解包: tar xvf FileName.tar 打包:tar cvf FileName.tar DirName    tar cvf a.tar a.txt b.txt c.txt (注:tar是打包,不是压缩!) --------------------------------------------- .gz 解压1:gunzip FileName.gz 解压2:gzip -d FileName.gz 压缩:g

支持文件的流式压缩/解压IP*Works! Zip

IP*Works! Zip是为应用程序添加压缩功能的完全可控件组件包.使用简单.速度快并且效率很高,是一个为桌面和网上应用程序添加压缩和解压缩功能的组件套包./n software IP*Works! Zip支持Zip.Tar.Gzip 和 Jar压缩标准,特别的,它支持流式压缩.加密压缩,在压缩包里就可以直接删除文件.我们目前提供完全可控的纯C# .NET组件.纯Java Beans. 产品特征: IP*Works! Zip基于纯C#代码,是完全可控的.NET组件,不依赖于任何外部代码.是完全

Lucene4.2源码解析之fdt和fdx文件的读写——fdx文件存储一个个的Block,每个Block管理着一批Chunk,通过docID读取到document需要完成Segment、Block、Chunk、document四级查询,引入了LZ4算法对fdt的chunk docs进行了实时压缩/解压

前言 通常在搜索打分完毕后,IndexSearcher会返回一个docID序列,但是仅仅有docID我们是无法看到存储在索引中的document,这时候就需要通过docID来得到完整Document信息,这个过程就需要对fdx/fdt文件进行读操作.为了更清楚地了解fdx/fdt文件的作用,本文把fdx/fdt文件的读和写整合到了一起,尽管这在Lucene中是两个分开的过程. 1. 索引生成阶段 索引生成阶段包含着一个复杂的过程,所以了解本文前最好对Lucene的索引架构有一定的了解,可以参考博

linux下各种文件压缩解压(转载)

Linux下最常用的打包程序就是tar了,使用tar程序打出来的包我们常称为tar包,tar包文件的命令通常都是以.tar结尾的.生成tar包后,就可以用其它的程序来进 行压缩了,所以首先就来讲讲tar命令的基本用法:  tar命令的选项有很多(用man tar可以查看到),但常用的就那么几个选项,下面 来举例说明一下:  # tar -cf all.tar *.jpg  这条命令是将所有.jpg的文件打成一个名为all.tar的包.-c是表示产生新的包 ,-f指定包的文件名.  # tar -

Centos压缩&解压

centos中的文件压缩与解压用得频率还是较大的,许多的压缩软件都是下载到linux系统上,然后解压安装,使用的是 tar 命令,这个命令又有主选项和辅助选项,这里就来总结一下吧,以方便自己的使用. Tar 语法:tar [主选项+辅选项] 文件或者目录 主选项: c 创建新的档案文件.如果用户想备份一个目录或是一些文件,就要选择这个选项.相当于打包. x 从档案文件中释放文件.相当于拆包. t 列出档案文件的内容,查看已经备份了哪些文件. 特别注意,在参数的下达中, c/x/t 仅能存在一个!

SAPCAR 压缩解压软件的使用方法

SAPCAR 是 SAP 公司使用的压缩解压软件,从 SAP 网站下载的补丁包和小型软件基本都是扩展名为 car 或 sar 的,它们都可以用 SAPCAR 来解压.下面是它的使用说明: 用法: 创建新档案:SAPCAR -c[vir][f archive] [-P] [-C directory]   [-A filename] [-T filename] [-X filename]   [-p value] [-V] file1 file2 ... 列出一个档案的内容:SAPCAR -t[vs