nginx使用gzip压缩文件

Posted 我就是程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nginx使用gzip压缩文件相关的知识,希望对你有一定的参考价值。

团队文化:进取,分享,快乐,责任!

团队愿景:做最好的产品,打造有影响力的团队!

一个热爱技术,气氛活跃,开放分享的团队,长期招聘架构师,高级java开发工程师,高级前端开发工程师数名,期待你的加入,简历投递:panjian@jd.com


为了提高页面的响应速度,可以从设置 nginx 的 gzip 和缓存这2方面入手,而为ttf,js,css等文件开启 gzip 和缓存能大大减少带宽的消耗.

HTTP 的内容编码机制

Accept-Encoding 和 Content-Encoding 是 HTTP 中用来对[采用何种编码格式传输正文]进行协定的一对头部字段. 它的工作原理是这样:

 
   
   
 
  1. 浏览器发送请求时,通过 Accept-Encoding 带上自己支持的内容编码格式列表;

  2. 服务端从中挑选一种用来对正文进行编码,并通过 Content-Encoding 响应头指明选定的格式;

  3. 浏览器拿到响应正文后,依据 Content-Encoding 进行解压.

  4. 当然,服务端也可以返回未压缩的正文,但这种情况不允许返回 Content-Encoding;

  5. 这个过程就是 HTTP 的内容编码机制.

Accept-Encoding,作为请求首部字段,可以一次性指定多种内容编码,比如:

 
   
   
 
  1. 1.gzip

  2.    由文件压缩程序gzip(GNU zip)生成的编码格式(RFC1952),采用Lempel-Ziv算法(LZ77)及32位冗余校验(Cyclic Redundancy Check,统称CRC);

  3.    文章后面会统一介绍gzip的算法;

  4. 2.compress

  5.    UNIX文件压缩程序compress生成的编码格式,采用Lempel-Ziv-Welch算法(LZW);

  6. 3.deflate

  7.    组合使用zlib格式(RFC1950)及由default压缩算法(RFC1951)生成的编码格式;

  8. 4.identity

  9.    不执行压缩或者不会变化的默认编码格式.

Content-Encoding作为实体首部字段,采用的内容编码格式和Accept-Encoding是相对应的.

在nginx上添加以下逻辑,用来压缩字体文件,以达到节省网络带宽,提高网站速度的作用.

 
   
   
 
  1.    #字体有很多格式,为匹配字体格式的文件进行压缩设置

  2.    #就是拦截这种请求,然后压缩:www.test.com/dist/aabbccddeeffgg.ttf

  3.    location ~* ^/dist/.+\.(eot|ttf|otf|woff|svg)$ {

  4.        #不缓存

  5.        expires                 0;

  6.        #增加type对应类型

  7.        types {

  8.            application/vnd.ms-fontobject eot;

  9.            font/ttf ttf;

  10.            font/opentype otf;

  11.            font/x-woff woff;

  12.            image/svg+xml svg;

  13.        }

  14.        # 开启gzip

  15.        gzip  on;

  16.        # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩

  17.        gzip_min_length 1k;

  18.        # 设置压缩所需要的缓冲区大小

  19.        gzip_buffers 4 16k;

  20.        #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)

  21.        gzip_http_version 1.0;

  22.        #压缩等级 1-9 等级越高,压缩效果越好,节约宽带,但CPU消耗大

  23.        gzip_comp_level 3;

  24.        # 进行压缩的文件类型,默认就已经包含text/htmljavascript有多种形式。其中的值可以在 mime.types 文件中找到。

  25.        gzip_types font/ttf font/opentype font/x-woff image/svg+xml;

  26.        # 是否在http header中添加Vary: Accept-Encoding,建议开启

  27.        gzip_vary on;

  28.        # 禁用IE 6 gzip , 因为IE6的某些版本对gzip的压缩支持很不好,会造成页面的假死

  29.        gzip_disable "MSIE [1-6].";

  30.    }

测试结果:

nginx使用gzip压缩文件

用curl测试gzip是否开启成功

 
   
   
 
  1. curl -I -H "Accept-Encoding: gzip, deflate" "http://www.test.com/dist/aabbccddeeffgg.ttf"

 
   
   
 
  1. gzip未开启:

  2. TP/1.1 200 OK

  3. Server: JDWS/1.0.0

  4. Date: Tue, 21 Aug 2018 01:49:24 GMT

  5. Content-Length: 18520

  6. Connection: close

  7. Last-Modified: Mon, 20 Aug 2018 09:40:38 GMT

  8. Accept-Ranges: bytes

  9. Expires: Tue, 21 Aug 2018 01:49:24 GMT

  10. Cache-Control: max-age=0

 
   
   
 
  1. gzip开启:

  2. TP/1.1 200 OK

  3. Server: JDWS/1.0.0

  4. Date: Tue, 21 Aug 2018 01:48:10 GMT

  5. Content-Type: font/ttf

  6. Last-Modified: Fri, 10 Aug 2018 06:13:07 GMT

  7. Connection: close

  8. Vary: Accept-Encoding

  9. Expires: Tue, 21 Aug 2018 01:48:10 GMT

  10. Cache-Control: max-age=0

  11. Content-Encoding: gzip

gzip压缩算法:

 
   
   
 
  1. gzip是一种数据压缩格式,或者说是一种文件格式,用.gz结尾;

  2. gzip可以极大的加速网站.有时压缩比率高达80%,一般最少都有40%左右;

  3. 对于要压缩的文件,使用gzip,主要分为两步:

  4. 1.使用LZ77压缩算法进行压缩,得到初始结果;

  5. 2.使用Haffman编码对初始结果进行再压缩,得到最终结果.

详细说下这两种算法:

LZ77算法

 
   
   
 
  1.    这个算法是由Jacob Ziv Abraham Lempel 1977 年提出,所以命名为 LZ77.

  2. 整体思路:

  3.    我们认为是一段内容总会有重复的内容,后面重复的内容可以用两者之间的距离加内容长度联合替换,

  4.    而替换后的内容的所占空间一般都会比原内容小,重复越多,压缩完空间就越小.

  5. 详细实现过程:

  6.    先介绍三个概念:

  7.        1.待编码区(字符从这里进来);

  8.        2.已编码区(字符从这里出去,也叫缓冲区);

  9.        3.滑动窗口(左边是已编码区,右边是待编码区,字符会从右向左依次被读取).

  10.        |        滑动窗口       |

  11.        |  已编码区   | 待编码区 |

           |            | a   a   b| c  b  b  a  b  c

  12.    再看看大概步骤:

  13.        1.字符a从待编码区进来,此时a在待编码区的最左边;

  14.        2.在待编码区查找从这个a字符在已编码区的最大匹配长度;

  15.        3.如果能找到,就输出(偏移量m,最大匹配长度n),滑动窗口向右偏移n个位置;

  16.            偏移量m就是待编码区的字符a到已编码区匹配到的字符a的移动距离;

  17.            最大匹配长度n就是待编码区有多少连续字符可以在已编码区找到匹配的,这些连续字符的长度;

  18.        4.如果找不到,就输出(0,0,a),滑动窗口向右偏移1位;

  19.        5.直到待编码区为空,就停止编码,否则继续从2开始循环.

以上面的字符串为例,举个简单易懂的例子:

第一步:a到待编码区的最左边了,在已编码区没有找到匹配的字符,输出(0,0,a), 如下图所示

nginx使用gzip压缩文件

滑动窗口准备右移一位,到第二步.

第二步:开始编码,待编码区的第一个字符是a,在已编码区查找匹配字符,找到了; 继续在待编码区读到ab两个字符,在已编码区查找匹配字符,没找到; 所以本次编码待编码区的第一个字符a,输出(1,1); 第一个1代表待编码区的a到已编码区的偏移量,偏移一位,记为1; 第二个1代表本次可编码的长度,因为只有一个a,所以记为1. 如下图所示

nginx使用gzip压缩文件

滑动窗口准备右移一位,到第三步.

第三步:待编码区第一个字符是b,在已编码区查找匹配字符,没找到; 同第一步,输出(0,0,b). 如下图所示

nginx使用gzip压缩文件

滑动窗口准备右移一位,到第四步.

第四步:待编码区第一个字符是c,在已编码区查找匹配字符,没找到; 同第一步,输出(0,0,c). 如下图所示

nginx使用gzip压缩文件

滑动窗口准备右移一位,到第五步.

第五步:待编码区第一个字符是b,在已编码区查找匹配字符,找到了; 待编码区前两个字符是bb,在已编码区查找匹配字符,没找到; 所以本次编码待编码区的第一个字符b,输出(2,1). 如下图所示

nginx使用gzip压缩文件

滑动窗口准备右移一位,到第六步.

第六步:待编码区第一个字符是b,在已编码区查找匹配字符,找到了; 待编码区前两个字符是ba,在已编码区查找匹配字符,没找到; 所以本次编码待编码区的第一个字符b,输出(3,1). 如下图所示

nginx使用gzip压缩文件

滑动窗口准备右移一位,到第七步.

第七步:待编码区第一个字符是a,在已编码区查找匹配字符,找到了; 待编码区前两个字符是ab,在已编码区查找匹配字符,找到了; 待编码区前三个字符是abc,在已编码区查找匹配字符,找到了; 这个例子待编码区只有三个字符的长度,实际会很长,就一直找,直到找不到匹配字符为止; 所以本次编码待编码区的前三个字符abc,输出(5,3). 如下图所示

nginx使用gzip压缩文件

滑动窗口准备右移三位,到第八步.

第八步:待编码区没有字符了,结束

nginx使用gzip压缩文件

最终结果:(0,0,a)(1,1)(0,0,b)(0,0,c)(2,1)(3,1)(5,3) 通过这个结果反向解码,也能得到原文: aabcbbabc 而且解码比编码还要快很多,主要是因为少了匹配这一步.

Haffman编码

 
   
   
 
  1. 整体思路:

  2.    我们知道,普通的编码都是定长的,比如ASCII编码,每个字符编码后的长度都是固定长度,

  3. 在解码的时候也就相对简单,只需按照定长将码解开,逐个翻译成对应的字符即可;

  4.    haffman采用的是可变长编码,目的是为了让出现次数多的字符采用更少的长度来存储,

  5. 这样就可能会大大加强压缩力度;

  6.    haffman建立了树的概念,haffman树是一种二叉树,将所有符号都对应到树的叶子节点上,

  7. 每个叶子节点都是可以唯一表示的,都是用若干个01组成的;

  8.    由于所有的字符最终都会落在叶子节点上,即任何字符的编码都不会是其他字符编码的前缀,

  9. 所以在解析的时候,也不会发生混淆的问题,因此haffman编码后的码,也是一种唯一可译码.

  10. 详细实现过程:

  11.    1.先读所有文件,将所有内容中所有字符出现的次数统计出来做排序;

  12.    2.我们将出现少的两个字符作为子节点,可以确定一个父节点,值就是两个子节点的次数和;

  13.    3.将上一步的父节点当做一个子节点,再重复执行第二步,直到所有节点全部用完,构成一颗大树;

  14.    4.每个数从父节点开始,默认左边的子节点是0,右边的子节点是1,

  15.      那么所有的字符对应的子节点都会有唯一的标识了;

  16.    5.用这些唯一标识来代替原来的字符,就是编码后的结果;

  17.    6.解码的时候,也是先根据所有字符的次数构成那颗大树,然后根据大树找出对应的字符即可.

举个简单易懂的例子: 比如文件的内容是:abbbbccccddde 我们可以统计出: a出现1次; b出现4次; c出现4次; d出现3次; e出现1次;

第一步:找出所有字符出现的次数. 如下图所示

nginx使用gzip压缩文件

第二步:找出两个最小次数的字符,构成一颗树; a字符和e字符都只出现1次,次数最少,构成一颗树; 产生新的节点,个数为a和e次数的和,即为1+1=2. 如下图所示

nginx使用gzip压缩文件

第三步:再找出剩下的节点中出现次数最小的两个节点; 找出d字符和上一步的新节点,分别一个是3次,一个是2次; 这两个节点继续壮大这颗树,再产生新的节点,次数为3+2=5次. 如下图所示

nginx使用gzip压缩文件

第四步:再从剩下的节点中找出最小的两个,是b和c 构成新的树,父节点是4+4=8 如下图所示

nginx使用gzip压缩文件

第五步:将最后两个节点合并成一颗大树; 最上面是树的根节点; 最下面是每个字符对应的子节点; 我们默认为:从根节点自上向下看开始计数,往左拐记为0,往右拐记为1; 那么从根节点到下面每个子节点的路径所对应的计数的组合,就是这个字符所要代替的01组合. 如下图所示

nginx使用gzip压缩文件

最终不难看出: a对应110 b对应00 c对应01 d对应10 e对应111 那么原内容:abbbbccccddde 就可以替换为:1100000000001010101101010111 这个就是压缩后的内容, 那么在解压的时候,再将这些10的组合依次替换成对应的字符即可.
















以上是关于nginx使用gzip压缩文件的主要内容,如果未能解决你的问题,请参考以下文章

Nginx配置之Gzip压缩

vue-cli + nginx项目开启gzip压缩

nginx开启gzip

nginx开启gzip

nginx使用gzip压缩文件

前端打包gzip + nginx开启静态gzip