一、gZip简单介绍
1.1 什么是gzip
gzip是GNUzip的缩写,最早用于UNIX系统的文件压缩。HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip。目前主流的浏览器,Chrome,firefox,IE等都支持该协议。常见的服务器如Apache,Nginx,IIS同样支持gzip。
gzip压缩比率在3到10倍左右,可以大大节省服务器的网络带宽。而在实际应用中,并不是对所有文件进行压缩,通常只是压缩静态文件。
1.1.1 gzip工作原理图
1.1.2 gzip的工作过程
浏览器请求url,并在request header中设置属性accept-encoding:gzip。表明浏览器支持gzip。
服务器收到浏览器发送的请求之后,判断浏览器是否支持gzip,如果支持gzip,则向浏览器传送压缩过的内容,不支持则向浏览器发送未经压缩的内容。一般情况下,浏览器和服务器都支持gzip,response headers返回包含content-encoding:gzip。
浏览器接收到服务器的响应之后判断内容是否被压缩,如果被压缩则解压缩显示页面内容。
1.2 为什么要开启gZip
我们给某人发送邮件时,我们在传输之前把自己的文件压缩一下,接收方收到文件后再去解压获取文件。这中操作对于我们来说都已经司空见惯。我们压缩文件的目的就是为了把传输文件的体积减小,加快传输速度。我们在 http 传输中开启 gZip 的目的也是如此,但是一般文章介绍 gZip 时候总是结合一些服务端配置(nginx)或者构建工具插件(webpack)来说,列出一大堆配置让人看的云里雾里,以至于到最后还没搞懂 为什么用,怎么用 这些问题。
1.3 gZip 文件怎么通讯
我们传输压缩文件给别人时候一般都带着后缀名 .rar, .zip之类,对方在拿到文件后根据相应的后缀名选择不同的解压方式然后去解压文件。我们在 http 传输时候解压文件的这个角色的扮演者就是我们使用的浏览器,但是浏览器怎么分辨这个文件是什么格式,应该用什么格式去解压呢?
在 http/1.0 协议中关于服务端发送的数据可以配置一个 Content-Encoding 字段,这个字段用于说明数据的压缩方法
Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate
客户端在接受到返回的数据后去检查对应字段的信息,然后根据对应的格式去做相应的解码。客户端在请求时,可以用 Accept-Encoding 字段说明自己接受哪些压缩方法。
Accept-Encoding: gzip, deflate
我们在浏览器的控制台中可以看到请求的相关信息
兼容性
提到浏览器作为一个前端就不由自主的会想一个问题,会不会有浏览器不支持呢。HTTP/1.0 是1996年5月发布的。好消息是基本不用考虑兼容性的问题,几乎所有浏览器都支持它。值得一提的是 ie6的早起版本中存在一个会破坏 gZip的错误,后面 ie6本身在 WinXP SP2 中修复了这个问题,而且用这个版本的用户数量也很少。
1.4 谁去压缩文件
这件事看起来貌似只能服务端来做,我们在网上看到最多的也是诸如 nginx 开启 gZip 配置之类的文章,但是现在前端流行 spa 应用, 用 react, vue 之类的框架时候总伴随这一套自己的脚手架,一般用 webpack 作为打包工具,其中可以配置插件 如compression-webpack-plugin 可以让我们把生成文件进行 gZip 等压缩并生成对应的压缩文件,而我们应用在构架时候有可能也会在服务区和前端文件中放置一层 node 应用来进行接口鉴权和文件转发。nodejs中我们熟悉的express 框架中也有一个compression 中间件,可以开启gZip,一时间看的人眼花缭乱,到底应该用谁怎么用呢?
- 服务端响应请求时候压缩
其实 nginx 压缩和 node 框架中用中间件去压缩都是一样的,当我们点击网页发送一个请求时候,我们的服务端会找到对应的文件,然后对文件进行压缩返回压缩后的内容【当然可以利用缓存减少压缩次数】,并配置好我们上面提到的 Content-Encoding 信息。对于一些应用在构架时候并没有上游代理层,比如服务端就一层 node 就可以直接用自己本身的压缩插件对文件进行压缩,如果上游配有有 nginx 转发处理层,最好交给 nginx 来处理这些,因为它们有专门为此构建的内容,可以更好的利用缓存并减小开销(很多使用c语言编写的)。
我们看一些 nginx 中开启 gZip 压缩的一部分配置
# 开启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),因为我们只有在上线项目时候才回去打包构建一次,所以我们在构建时候使用最高级的压缩方式压缩多耗费一些时间对我们来说根本没任何损耗,而我们在服务器上也不用再去压缩文件,只需要找到相应已经压缩过的文件直接返回就可以了。
3. 服务端怎么找到这些文件
在应用层面解决这个问题还是比较简单的,比如上述压缩文件会产生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后缀的文件是否存在,再去根据结果返回不同的内容。
1.5 哪些文件可以被 gZip 压缩
gZip 可以压缩所有的文件,但是这不代表我们要对所有文件进行压缩,我们写的代码(css,js)之类的文件会有很好的压缩效果,但是图片之类文件则不会被 gzip 压缩太多,因为它们已经内置了一些压缩,一些文件(比如一些已经被压缩的像.zip文件那种)再去压缩可能会让生成的文件体积更大一些。当然已经很小的文件也没有去压缩的必要了。
能开启 gZip 肯定是要开启的,具体使用在请求时候实时压缩还是在构建时候去生成压缩文件,就要看自己具体业务情况。
二、优化思路
zip 文件由哪端生成?
这个是一个问题,网上大部分教程会告诉你,在服务端配置nginx, 然后 xxx 一波操作猛如虎。 但是对于新手来说,这样真的好吗?不告诉人家原理,是不行的。
2.1 服务端生成
zip 文件可以服务端生成,例如:
2.1.1 nginx
nginx 有一个模块是 gzip 模块,然后你只要开启了,nginx就会帮你来把数据(静态资源 和 接口数据)进行压缩,然后传入到客户端,客户端来解压,然后在进行代码的读取,其实这一步就是节约带宽,减少传输的代码包的数量。从而节约传输时间。然后网站就能很快打开了。
2.1.2 node
node也有相关于 compression 的库,然后配置一些选项,来选择对数据(资源和接口数据)的压缩,这个是同一个道理,就是服务端来进行压缩嘛,然后在传输。
其他的服务也有相关的库,怎么使用要看对于的语言了,这里就不展开。
2.2 客户端生成
既然 服务端可以生成gzip文件, 那些构建工具 webpack, rollup, 等为啥也要写一些压缩的包? 而且会发现包好像周下载量还停高的。
例如:
为啥要客户端生成呢?
问得好, 我们知道服务端生成是不是每一次请求都要去请求服务器,然后服务器来生成压缩包。服务器每一次生成压缩包是不是会不会浪费服务端的性能哇!, 如果客户端生成,服务端先判断是否存在的后缀名为zip的文件,直接去拿,不存在再压缩,这样是不是把服务器每一次都要压缩的事情,交给客户端了呢? 虽然客户端打包进行代码压缩会很慢。 但是我们打包只是发布代码的时候打一次包,而服务器是要面对成千上万的人来访问等。 说到这里大家应该明白了吧。
三、优化实战
服务器主要使用windows服务器,配合IIS使用,nginx也会简单介绍下配置。
3.1 服务端压缩
对于服务端来进行压缩,客户端啥也不用做,只需要把打好的包放入对应的目录下面,然后在访问的时候 nginx 自动进行压缩传给客户端进行解析等。
3.1.1 nginx配置
使用HttpGzip(这个模块支持在线实时压缩输出数据流)模块.
下面这一段命令的作用域是 : http, server, location, 意思是在 http, server, location 这三个地方加入到哪个地方都行,为了不影响其他的,个人建议加到 location模块,这样其他的就不会影响了。
gzip on;
gzip_buffers 4 16k;
gzip_comp_level 6;
gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php;
效果
主要加载的是这个应用
3.2 客户端压缩
在客户的压缩工具也有很多,这里我就介绍webpack 和 vite 客户端怎么进行压缩然后部署。
3.2.1 webpack
1. 使用Gzip
用npm安装gzip插件
//安装低版本
npm install --save-dev compression-webpack-plugin
在vue.config.js中配置,引入插件
//引入gzip压缩插件
const CompressionPlugin = require('compression-webpack-plugin')
使用插件,在vue.config.js文件中configureWebpack的plugins中添加配置new CompressionPlugin(…)或如下在最后加入
configureWebpack:config => {if(process.env.NODE_ENV === "production"){return {plugins:[new CompressionPlugin({algorithm: 'gzip', // 使用gzip压缩test: /\.js$|\.html$|\.css$/, // 匹配文件名filename: '[path][base].gz[query]', // 压缩后的文件名(保持原文件名,后缀加.gz)minRatio: 0.8,threshold: 10240, // 对超过10k的数据压缩,一般都会选择大于1字节的进行压缩,小于1字节可能压缩后反而体积更大了deleteOriginalAssets: false, // 是否删除未压缩的源文件,谨慎设置,如果希望提供非gzip的资源,可不设置或者设置为false(比如删除打包后的gz后还可以加载到原始资源文件)}),]}}},
2. 打包发布
插件导入后,npm run build打包,在dist文件夹中查看,可以看到.gz格式的文件
压缩前后文件大小对比![
把打包好的静态文件部署在服务器,使用链接访问网页,发现加载时间需要十几秒
dist文件在IIS发布后,选择压缩
开启静态内容压缩(不建议选中压缩应用程序文件,但一定要选上压缩静态文件,不然就等于没有压缩,达不到负载均衡了。)
另一篇文章看见的开启操作,实际上我没做下方引用部分的内容:
- 然后选中我那个站下面那个服务器扩展,新建一个服务器扩展,名字为GZIP,下面的添加文件路径为:c:\windows\system32\inetsrv\gzip.dll,然后启用这个扩展。
- 我们要修改配置文件,在配置文件之前要停止IIS服务,(提醒大家一定要先关闭IIS服务)打开C:\Windows\System32\inetsrv\MetaBase.xml,这个文件很大,找到下面一段信息
<IIsCompressionScheme Location ="/LM/W3SVC/Filters/Compression/gzip"<br> <br><br>HcCompressionDll="%windir%\system32\inetsrv\gzip.dll"<br> <br><br>HcCreateFlags="1"<br><br><br> HcDoDynamicCompression="TRUE"<br> <br><br>HcDoOnDemandCompression="TRUE"<br><br><br> HcDoStaticCompression="TRUE"<br> <br><br>HcDynamicCompressionLevel="6"<br> <br><br>HcFileExtensions="htm<br><br>html<br><br>txtjscss"<br><br><br> HcOnDemandCompLevel="10"<br> <br><br>HcPriority="1"<br><br><br> HcScriptFileExtensions="asp<br><br>dll<br><br>exe"<br><br>><br><br><br></IIsCompressionScheme><br><IIsCompressionScheme Location ="/LM/W3SVC/Filters/Compression/deflate"<br> HcCompressionDll="%windir%\system32\inetsrv\gzip.dll"<br> HcCreateFlags="0"<br> HcDoDynamicCompression="TRUE"<br> HcDoOnDemandCompression="TRUE"<br> HcDoStaticCompression="true"<br> HcDynamicCompressionLevel="9"<br> HcFileExtensions="htm<br> html<br> txt<br> js<br> css <br> swf<br> xml"<br> HcOnDemandCompLevel="9"<br> HcPriority="1"<br> HcScriptFileExtensions="asp <br> aspx<br> dll<br> exe"<br> ><br></IIsCompressionScheme><br><IIsCompressionScheme Location ="/LM/W3SVC/Filters/Compression/gzip"<br> HcCompressionDll="%windir%\system32\inetsrv\gzip.dll"<br> HcCreateFlags="1"<br> HcDoDynamicCompression="TRUE"<br> HcDoOnDemandCompression="TRUE"<br> HcDoStaticCompression="true"<br> HcDynamicCompressionLevel="9"<br> HcFileExtensions="htm<br> html<br> txt<br> js<br> css <br> swf<br> xml"<br> HcOnDemandCompLevel="9"<br> HcPriority="1"<br> HcScriptFileExtensions="asp <br> aspx<br> dll<br> exe"<br> ><br></IIsCompressionScheme>
修改这个文件是要增加一些要进行压缩的文件后缀,其中 HcFileExtensions 是静态文件的扩展名,增加 js 和 css
等;HcScriptFileExtensions 为动态文件的扩展名,增加
aspx,HcDynamicCompressionLevel改成9,(0-10,6是性价比最高的一个)。 重启一下IIS服务
如果IIS里启用动态内容压缩是灰色的,则需要在服务器上安装下:
在windows【服务管理】中,选择【增加功能和角色】
,然后在服务器角色中,按下图操作
安装完成后,在IIS中看到的【启用动态内容压缩】不再为灰选状态,表示安装成功。
此时访问,可以看到浏览器,查看chunk.js的网络请求的回应,发现已经有了content-encoding的压缩回应,为gzip格式
关于vue配置gZip的更详细配置:https://segmentfault.com/a/1190000024497914
3.2.2 vite
本人项目是使用vite来进行构建的
这里也需要安装一个插件, 一开始我以为是 rollup-plugin-gzip 后面发现不对,vite 自己做了一个插件出来。vite-plugin-compression 使用方式很简单
import viteCompression from 'vite-plugin-compression';
plugins: [viteCompression()],
效果如下:
nginx 配置
没错,这里nginx 也要配置, 配置启动gzip模块, 然后优先使用本地压缩好的文件。
gzip_static on;
gzip_http_version 1.1;
gzip_proxied expired no-cache no-store private auth;
效果