概念初探
Gzip,全称为 GNU zip,是一种无损压缩文件的算法。其底采用的是 DEFLATE,而 DEFLATE 是 LZ77 与 哈夫曼编码 的一个组合体。
通常来说,“Gzip 压缩”的整体实现流程如下:
-
浏览器发送请求到服务器,服务器根据请求头中的
Accept-Encoding
字段判断该浏览器是否支持Gzip压缩。如果不支持,则只响应未经压缩的资源即可;如果支持,则进入后续流程。-
方案一:
服务器端根据接口路径,读取存储在本地的、原始的、未经压缩的静态资源,然后在内存中对其进行“Gzip压缩”,并将压缩后的结果放在响应体中返回给浏览器(响应头中的
Content-Encoding
字段的值应为gzip
)。 -
方案二:
服务器端根据接口路径,读取存储在本地的、被“Gzip压缩”后的静态资源(即使用 Webpack 配合
compression-webpack-plugin
对静态资源进行预压缩),并直接将其放在响应体中返回给浏览器(响应头中的Content-Encoding
字段的值应为gzip
)。
-
-
浏览器接收到服务器端返回的结果后,会判断响应头中的
Content-Encoding
字段的值是否为gzip
。如果是,则自动将其进行“unGzip”解压,之后在进行其他处理。
经过实践可以发现:开启“Gzip 压缩”后,静态资源的传输效率会得到大幅提升。以我的“全栈个人博客项目”为例,其开启“Gzip压缩”前后各文件的体积大小如下所示:(不难看出,文件的体积越大,压缩效果就越明显)
但是,服务器的压缩需要时间,浏览器端的解压也需要时间。
在“方案一”中,如果服务器端需要响应的静态资源很多,或同时有大量的用户访问服务器端并请求静态资源,那么服务器端的压力就会剧增,因为每次响应一个静态资源之前,都需要将其读到内存并进行“Gzip”压缩,然后才返回给浏览器端,会产生大量冗余操作。
因此,推荐采用“方案二”,以解决上述问题。即使用 Webpack 配合compression-webpack-plugin
插件,在前端工程的打包阶段,对静态资源进行“预压缩”,从而移除服务器端的压缩时间。
开始行动
本次案例所用项目为:全栈个人博客项目 。
前端工程使用的是
Vue 2.6.11
、@vue/cli 4.5.0
,后端工程使用的是NodeJS
、Express
。
前端侧
在工程根目录下,新建vue.config.js
文件。先进行如下配置:
module.exports = {
productionSourceMap: false // 生产环境下关闭源码地图,即不生产对应的map文件,减小打包结果的体积
};
执行npm install compression-webpack-plugin@5.0.0 --save-dev
命令,在开发环境下安装compression-webpack-plugin
插件。
注意:此处的插件是安装的 5.0.0 版本。因为如果安装最新或较高的版本,在运行
npm run build
进行打包时,会报如下错误:TypeError: Cannot read properties of undefined (reading 'tapPromise')
打开vue.config.js
文件,配置上述插件以开启“Gzip 压缩”,详细内容如下:
const CompressionPlugin = require("compression-webpack-plugin");
module.exports = {
productionSourceMap: false,
configureWebpack: config => {
// 生产环境下:开启Gzip预压缩
if(process.env.NODE_ENV === 'production') {
const gzipExtList = ['html', 'css', 'js']; // 需要Gzip压缩的文件白名单(可自定义)
config.plugins.push(
new CompressionPlugin({ // 配置Gzip压缩的插件
filename: "[path].gz[query]", // 默认值
algorithm: "gzip", // 默认值
test: new RegExp(`.(${gzipExtList.join('|')})$`),
threshold: 10240, // 只有体积大于 10KB 的资源会被处理(默认值为 0)
minRatio: 0.8, // 默认值,只有压缩率优于 0.8 的资源才会被处理(Compressed Size / Original Size)
deleteOriginalAssets: false // 是否删除原文件(默认值为 false)
}),
);
}
}
};
后端侧
在本案例所使用的项目中,静态文件资源是存放在使用了express
的后端工程的public
目录中,并直接交由该Node服务器的express 静态资源中间件
进行管理,不直接依赖 Nginx。
因此,直接使用express-static-gzip
中间件即可配合前端开启”Gzip 压缩“。该插件的使用方法如下:
const express = require('express');
const path = require('path');
const app = express();
const staticRoot = path.resolve(__dirname, '../public');
const expressStaticGzip = require("express-static-gzip"); // ★引入express-static-gzip插件★
app.use(expressStaticGzip(staticRoot)); // ★开启Gzip压缩资源的响应★
拓展
如果你的静态文件是用 Nginx 管理的,那么只需要让 Nginx 根据请求来自己选择 .gz
文件输出。
利用 Nginx 中的http_gzip_static_module
模块,不消耗 CPU 资源,在服务器端进行如下操作即可。
-
执行
nginx -t
命令,查找nginx.conf
配置文件所在位置 -
执行
cd
命令,进入该配置文件所在路径 -
执行
vi nginx.conf
命令,修改该配置文件(添加如下代码)gzip_static on;
-
执行
nginx -s reload
命令,刷新 Nginx,便可成功开启。
注意:Nginx 中的
http_gzip_static_module
模块,默认是不存在的。因此,我们必须提前在 Nginx 中自行添加上该模块。戳我查看详细教程
功能测试
成功开启“Gzip 压缩”且重新完成部署后,可利用如下方法查看是否开启成功。
-
输入URL,访问对应的前端页面,并打开 Chrome 控制台
-
进入 Network 菜单页,便可以看到具体有哪些静态资源应用了“Gzip 压缩”
- 如果看不到上图标记处的信息,请戳 ○这里○ 查看解决方案!
参考文档
PS:本文内容仅供交流学习,转载请注明出处。