咱们给某人发送邮件时,咱们在传输以前把本身的文件压缩一下,接收方收到文件后再去解压获取文件。这中操做对于咱们来讲都已经司空见惯。咱们压缩文件的目的就是为了把传输文件的体积减少,加快传输速度。咱们在 http
传输中开启 gZip
的目的也是如此,可是通常文章介绍 gZip
时候老是结合一些服务端配置(nginx
)或者构建工具插件(webpack
)来讲,列出一大堆配置让人看的云里雾里,以致于到最后还没搞懂 为何用
,怎么用
这些问题。javascript
咱们下面去探讨一下这些问题css
gZip
文件怎么通信咱们传输压缩文件给别人时候通常都带着后缀名 .rar
, .zip
之类,对方在拿到文件后根据相应的后缀名选择不一样的解压方式而后去解压文件。咱们在 http
传输时候解压文件的这个角色的扮演者就是咱们使用的浏览器,可是浏览器怎么分辨这个文件是什么格式,应该用什么格式去解压呢?html
在 http/1.0
协议中关于服务端发送的数据能够配置一个 Content-Encoding
字段,这个字段用于说明数据的压缩方法前端
Content-Encoding: gzip Content-Encoding: compress Content-Encoding: deflate
客户端在接受到返回的数据后去检查对应字段的信息,而后根据对应的格式去作相应的解码。客户端在请求时,能够用 Accept-Encoding
字段说明本身接受哪些压缩方法。vue
Accept-Encoding: gzip, deflate
咱们在浏览器的控制台中能够看到请求的相关信息java
提到浏览器做为一个前端就不禁自主的会想一个问题,会不会有浏览器不支持呢。HTTP/1.0
是1996年5月发布的。好消息是基本不用考虑兼容性的问题,几乎全部浏览器都支持它。值得一提的是 ie6
的早起版本中存在一个会破坏 gZip
的错误,后面 ie6
自己在 WinXP SP2
中修复了这个问题,并且用这个版本的用户数量也不多。node
这件事看起来貌似只能服务端来作,咱们在网上看到最多的也是诸如 nginx
开启 gZip
配置之类的文章,可是如今前端流行 spa
应用, 用 react
, vue
之类的框架时候总伴随这一套本身的脚手架,通常用 webpack
做为打包工具,其中能够配置插件 如compression-webpack-plugin 可让咱们把生成文件进行 gZip
等压缩并生成对应的压缩文件,而咱们应用在构架时候有可能也会在服务区和前端文件中放置一层 node
应用来进行接口鉴权和文件转发。nodejs
中咱们熟悉的express
框架中也有一个compression 中间件,能够开启gZip
,一时间看的人眼花缭乱,到底应该用谁怎么用呢?react
其实 nginx
压缩和 node
框架中用中间件去压缩都是同样的,当咱们点击网页发送一个请求时候,咱们的服务端会找到对应的文件,而后对文件进行压缩返回压缩后的内容【固然能够利用缓存减小压缩次数】,并配置好咱们上面提到的 Content-Encoding
信息。对于一些应用在构架时候并无上游代理层,好比服务端就一层 node
就能够直接用本身自己的压缩插件对文件进行压缩,若是上游配有有 nginx
转发处理层,最好交给 nginx
来处理这些,由于它们有专门为此构建的内容,能够更好的利用缓存并减少开销(不少使用c语言编写的)。linux
咱们看一些 nginx
中开启 gZip
压缩的一部分配置webpack
# 开启gzip gzip on; # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩 gzip_min_length 1k; # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明 gzip_comp_level 2; # 进行压缩的文件类型。javascript有多种形式。其中的值能够在 mime.types 文件中找到。 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
既然服务端均可以作了为何 webpack
在打包前端应用时候还有这样一个压缩插件呢,咱们能够在上面 nginx
配置中看到 gzip_comp_level 2
这个配置项,上面也有注释写道 1-10
数字越大压缩效果越好,可是会耗费更多的CPU和时间,咱们压缩文件除了减小文件体积大小外,也是为了减小传输时间,若是咱们把压缩等级配置的很高,每次请求服务端都要压缩好久才回返回信息回来,不只服务器开销会增大不少,请求方也会等的不耐烦。可是如今的 spa
应用既然文件都是打包生成的,那若是咱们在打包时候就直接生成高压缩等级的文件,做为静态资源放在服务器上,接收到请求后直接把压缩的文件内容返回回去会怎么样呢?
webpack
的 compression-webpack-plugin
就是作这个事情的,配置起来也很简单只须要在装置中加入对应插件,简单配置以下
const CompressionWebpackPlugin = require('compression-webpack-plugin'); webpackConfig.plugins.push( new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp('\\.(js|css)$'), threshold: 10240, minRatio: 0.8 }) )
webpack
打包完成后生成打包文件外还会额外生成 .gz
后缀的压缩文件
那么这个插件的压缩等级是多少呢,咱们能够在源码中看到默认的 level
是 9
... const zlib = require('zlib'); this.options.algorithm = zlib[this.options.algorithm]; ... this.options.compressionOptions = { level: options.level || 9, flush: options.flush ... }
能够看到压缩使用的是 zlib
库,而 zlib
分级来讲,默认是 6 ,最高的级别就是9 Best compression (also zlib.Z_BEST_COMPRESSION)
,由于咱们只有在上线项目时候才回去打包构建一次,因此咱们在构建时候使用最高级的压缩方式压缩多耗费一些时间对咱们来讲根本没任何损耗,而咱们在服务器上也不用再去压缩文件,只须要找到相应已经压缩过的文件直接返回就能够了。
在应用层面解决这个问题仍是比较简单的,好比上述压缩文件会产生index.css
, index.js
的压缩文件,在服务端简单处理能够判断这两个请求而后给予相对应的压缩文件。以 node
的 express
为例
... app.get(['/index.js','/index.css'], function (req, res, next) { req.url = req.url + '.gz' res.set('Content-Encoding', 'gzip') res.setHeader("Content-Type", generateType(req.path)) // 这里要根据请求文件设置content-type next() })
上面咱们能够给请求返回 gZip
压缩后的数据了,固然上面的局限性太强也不可取,可是对于处理这个方面需求也已经有不少库存在,express
有 express-static-gzip 插件 koa
的 koa-static
则默认自带对 gZip
文件的检测,基本原理就是对请求先检测 .gz
后缀的文件是否存在,再去根据结果返回不一样的内容。
gZip
能够压缩全部的文件,可是这不表明咱们要对全部文件进行压缩,咱们写的代码(css,js
)之类的文件会有很好的压缩效果,可是图片之类文件则不会被 gzip
压缩太多,由于它们已经内置了一些压缩,一些文件(好比一些已经被压缩的像.zip文件那种)再去压缩可能会让生成的文件体积更大一些。固然已经很小的文件也没有去压缩的必要了。
能开启 gZip
确定是要开启的,具体使用在请求时候实时压缩仍是在构建时候去生成压缩文件,就要看本身具体业务状况。