什么是gzip
gzip就是GNUzip的缩写,也是一个文件压缩程序,可以将文件压缩进后缀为.gz的压缩包。而我们前端所讲的gzip压缩优化,就是通过gzip这个压缩程序,对资源进行压缩,从而降低请求资源的文件大小。
gzip压缩优化在业界的应用有多么普遍呢,基本上你打开任何一个网站,看它们的html,js,css文件都是经过gzip压缩的(即使js,css这类文件经过了混淆压缩之后,gzip仍然可以明显的优化文件体积。)。
Tips:通常gzip对纯文本内容可压缩到原大小的40%。但png、gif、jpg、jpeg这类图片文件并不推荐使用gzip压缩(svg是个例外),首先经过压缩后的图片文件gzip能压缩的空间很小。事实上,添加标头,压缩字典,并校验响应体可能会让它更大。
比如访问掘金,打开调试工具,在网络请求Network中,选择一个js或css,都能在Response Headers中找到 content-encoding: gzip 键值对,这就表示了这个文件是启用了gzip压缩的。
gzip压缩过程
此处我们用原生node写一个服务:
const http = require("http");
const fs = require("fs");
const server = http.createServer((req, res) => {
const rs = fs.createReadStream(`static${req.url}`); //读取文件流
rs.pipe(res); //将数据以流的形式返回
rs.on("error", err => {
//找不到返回404
console.log(err);
res.writeHead(404);
res.write("Not Found");
});
});
//监听8080
server.listen(8080, () => {
console.log("listen prot:8080");
});
用node server.js启动服务,此时我们访问 http://localhost:8080/xxx.js,网页会显示xxx.js文件的内容,查看Network面版,会发现xxx.js请求大小是88.73k,和原始资源文件大小一致,Response Headers中也没有 content-encoding: gzip ,说明这是未经过gzip压缩的。
如何开启gzip呢,很简单,node为我们提供了zlib模块,直接使用就行,上面的代码简单修改一下就可以。
const http = require("http");
const fs = require("fs");
const zlib = require("zlib"); // <-- 引入zlib块
const server = http.createServer((req, res) => {
const rs = fs.createReadStream(`static${req.url}`);
const gz = zlib.createGzip(); // <-- 创建gzip压缩
rs.pipe(gz).pipe(res); // <-- 返回数据前经过gzip压缩
rs.on("error", err => {
console.log(err);
res.writeHead(404);
res.write("Not Found");
});
});
server.listen(8080, () => {
console.log("listen prot:8080");
});
但是如果你尝试用编辑器打开这个文件,会发现打开失败或者提示这是一个二进制文件而不是文本。这个时候如果反应快的朋友可能会和我第一次的想法一样,试试把js后缀改成gz。因为前面说了,其实gzip就是一个压缩程序,将文件压缩进一个.gz压缩包。
原来gzip就是将资源文件压缩进一个压缩包,服务端返回压缩包的时候告诉浏览器一声,这其实是一个gz压缩包,浏览器你使用前先解压一下。而这个通知就是我们之前判断是否开启gzip压缩的请求头字段,Response Headers里的 content-encoding: gzip。
const http = require("http");
const fs = require("fs");
const zlib = require("zlib");
const server = http.createServer((req, res) => {
const rs = fs.createReadStream(`static${req.url}`);
const gz = zlib.createGzip();
res.setHeader("content-encoding", "gzip"); //添加content-encoding: gzip请求头。
rs.pipe(gz).pipe(res);
rs.on("error", err => {
console.log(err);
res.writeHead(404);
res.write("Not Found");
});
});
server.listen(8080, () => {
console.log("listen prot:8080");
此时浏览器再请求到gzip压缩后的文件,会先解压处理一下再使用。
gzip的注意点
前面说的哪些文件适合开启gzip压缩,哪些不适合是一个注意点。
还有一个注意点是,谁来做这个gzip压缩,我们的例子是在接到请求时,由node服务器进行压缩处理。这和express中使用compression中间件,koa中使用koa-compress中间件,nginx和tomcat进行配置都是一样的,这也是比较普遍的一种做法,由服务端进行压缩处理。
服务器了解到我们这边有一个 gzip 压缩的需求,它会启动自己的 CPU 去为我们完成这个任务。而压缩文件这个过程本身是需要耗费时间的,大家可以理解为我们以服务器压缩的时间开销和 CPU 开销(以及浏览器解析压缩文件的开销)为代价,省下了一些传输过程中的时间开销。
如果我们在构建的时候,直接将资源文件打包成gz压缩包,其实也是可以的,这样可以省去服务器压缩的时间,减少一些服务端的消耗。
比如我们在使用webpack打包工具的时候可以使用compression-webpack-plugin插件,在构建项目的时候进行gzip打包,详细的配置使用可以去看插件的文档,非常简单。
参考: