本文介绍了 GZIP 压缩技术的原理和工作机制,以及如何在 Nginx 服务器上进行配置以优化 Web 应用程序的性能。

GZIP

GZIP 是 GNU Zip 的缩写,最早应用于 UNIX 系统的文件压缩,现常应用于改进 Web 应用程序性能,其压缩比率在 3 到 10 倍左右,可大大节省服务器的网络带宽,具体说明可参照 RFC 1952 文档。

压缩原理

GZIP 使用 DEFLATE 算法进行压缩,流程如下:对于要压缩的文件,首先使用 LZ77 算法的一个变种进行压缩,随后对得到的结果进行 Huffman 编码。

LZ77 原理:如果文件中有两块内容相同的话,那么只要知道前一块的位置和大小,我们就可以确定后一块的内容。所以我们可以用(两者之间的距离,相同内容的长度)这样一对信息,来替换后一块内容。由于(两者之间的距离,相同内容的长度)这一对信息的大小,小于被替换内容的大小,所以文件得到了压缩。

Huffman 原理:读取整个文件,并统计每个符号(我们把字节的 256 种值看作是 256 种符号)的出现次数,建立建立 Huffman 树,得到每个符号的新编码。因此,对于文件中出现次数较多的符号,它的编码位数比较少;对于出现次数较少的符号,它的编码位数比较多。最后,我们把文件中的每个字节替换成各自的新编码。

工作机制

在前端应用中,GZIP 工作机制是一种 Content Negotiation

  • 浏览器请求 URL ,在 Request Headers 中设置 Accpet-Encoding:gzip 属性,表示浏览器支持 GZIP 压缩。
  • 服务器(Nginx 等)接收到请求后,判断浏览器是否支持 GZIP (根据 Accept Encoding 属性):若支持,则向浏览器发送压缩后的内容,服务器会在 Response Headers 中设置 Content-Encoding:gzip 属性;否则,发送未经压缩的内容。
  • 浏览器接收到服务器响应,根据 Content-Encoding 属性,判断返回的内容是否为已压缩过的:如果为已压缩内容,则解压缩

Nginx 设置

默认情况下,Nginx 自动启用了 GZIP 压缩,但只压缩 HTML 文件。我们执行以下命令,查看 Nginx 对 HTML 和 JavaScript 文件的压缩情况。

curl -H "Accept-Encoding:gzip" -I https://blog.jiahonzheng.cn

curl -H "Accept-Encoding:gzip" -I https://blog.jiahonzheng.cn/scripts/main.js

运行结果如下图,我们可以根据输出的 content-encoding 来判断响应是否为 GZIP 压缩内容:HTML 已开启 GZIP 压缩,JavaScript 文件未开启 GZIP 压缩。

我们可以修改 /etc/nginx/nginx.conf 文件,来全局修改 Nginx 的 GZIP 设置。

# 开启 GZIP
gzip on;
# 禁用 IE6 的 GZIP 选项,由于 IE6 的性能差,启用 GZIP 容易导致页面假死
gzip_disable "msie6";
# 设置响应头部,意在对于不支持 gzip 压缩的浏览器不进行压缩
gzip_vary on;
# Nginx 作为前端代理时启用该选项,表示无论后端服务器的 Headers 返回什么信息,都无条件启用压缩
gzip_proxied any;
# 压缩比,压缩比越高,压缩时间越长,消耗更多的 CPU 时间
gzip_comp_level 6;
# 设置系统使用多少个单位去缓存 GZIP 压缩数据流,与压缩速度有关,这里指原始数据以 8k 为单位的 16 倍申请内存
gzip_buffers 16 8k;
# 设置启用 GZIP 的 HTTP 协议版本
gzip_http_version 1.1;
# 启用 GZIP 压缩的文件类型
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss application/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;

在完成上述设置后,我们重新加载 Nginx ,并进行以下验证。

根据上述输出结果,我们成功开启了对 HTML 类型之外文件的 GZIP 支持。