為什么要開啟gZip
我們給某人發(fā)送郵件時,我們在傳輸之前把自己的文件壓縮一下,接收方收到文件后再去解壓獲取文件。這中操作對于我們來說都已經(jīng)司空見慣。我們壓縮文件的目的就是為了把傳輸文件的體積減小,加快傳輸速度。我們在 http
傳輸中開啟 gZip
的目的也是如此,但是一般文章介紹 gZip
時候總是結(jié)合一些服務(wù)端配置(nginx
)或者構(gòu)建工具插件(webpack
)來說,列出一大堆配置讓人看的云里霧里,以至于到最后還沒搞懂 為什么用
,怎么用
這些問題。
http 與 gZip
我們下面去探討一下這些問題
gZip
文件怎么通訊
我們傳輸壓縮文件給別人時候一般都帶著后綴名 .rar
, .zip
之類,對方在拿到文件后根據(jù)相應(yīng)的后綴名選擇不同的解壓方式然后去解壓文件。我們在 http
傳輸時候解壓文件的這個角色的扮演者就是我們使用的瀏覽器,但是瀏覽器怎么分辨這個文件是什么格式,應(yīng)該用什么格式去解壓呢?
在 http/1.0
協(xié)議中關(guān)于服務(wù)端發(fā)送的數(shù)據(jù)可以配置一個 Content-Encoding
字段,這個字段用于說明數(shù)據(jù)的壓縮方法
- Content-Encoding: gzip
- Content-Encoding: compress
- Content-Encoding: deflate
客戶端在接受到返回的數(shù)據(jù)后去檢查對應(yīng)字段的信息,然后根據(jù)對應(yīng)的格式去做相應(yīng)的解碼。客戶端在請求時,可以用 Accept-Encoding
字段說明自己接受哪些壓縮方法。
- Accept-Encoding: gzip, deflate
我們在瀏覽器的控制臺中可以看到請求的相關(guān)信息
兼容性
提到瀏覽器作為一個前端就不由自主的會想一個問題,會不會有瀏覽器不支持呢。HTTP/1.0
是1996年5月發(fā)布的。好消息是基本不用考慮兼容性的問題,幾乎所有瀏覽器都支持它。值得一提的是 ie6
的早起版本中存在一個會破壞 gZip
的錯誤,后面 ie6
本身在 WinXP SP2
中修復(fù)了這個問題,而且用這個版本的用戶數(shù)量也很少。
誰去壓縮文件
這件事看起來貌似只能服務(wù)端來做,我們在網(wǎng)上看到最多的也是諸如 nginx
開啟 gZip
配置之類的文章,但是現(xiàn)在前端流行 spa
應(yīng)用, 用 react
, vue
之類的框架時候總伴隨這一套自己的腳手架,一般用 webpack
作為打包工具,其中可以配置插件 如compression-webpack-plugin 可以讓我們把生成文件進(jìn)行 gZip
等壓縮并生成對應(yīng)的壓縮文件,而我們應(yīng)用在構(gòu)架時候有可能也會在服務(wù)區(qū)和前端文件中放置一層 node
應(yīng)用來進(jìn)行接口鑒權(quán)和文件轉(zhuǎn)發(fā)。nodejs
中我們熟悉的express
框架中也有一個compression 中間件,可以開啟gZip
,一時間看的人眼花繚亂,到底應(yīng)該用誰怎么用呢?
服務(wù)端響應(yīng)請求時候壓縮
其實 nginx
壓縮和 node
框架中用中間件去壓縮都是一樣的,當(dāng)我們點擊網(wǎng)頁發(fā)送一個請求時候,我們的服務(wù)端會找到對應(yīng)的文件,然后對文件進(jìn)行壓縮返回壓縮后的內(nèi)容【當(dāng)然可以利用緩存減少壓縮次數(shù)】,并配置好我們上面提到的 Content-Encoding
信息。對于一些應(yīng)用在構(gòu)架時候并沒有上游代理層,比如服務(wù)端就一層 node
就可以直接用自己本身的壓縮插件對文件進(jìn)行壓縮,如果上游配有有 nginx
轉(zhuǎn)發(fā)處理層,最好交給 nginx
來處理這些,因為它們有專門為此構(gòu)建的內(nèi)容,可以更好的利用緩存并減小開銷(很多使用c語言編寫的)。
我們看一些 nginx
中開啟 gZip
壓縮的一部分配置
- # 開啟gzip
- gzip on;
- # 啟用gzip壓縮的最小文件,小于設(shè)置值的文件將不會壓縮
- gzip_min_length 1k;
- # gzip 壓縮級別,1-10,數(shù)字越大壓縮的越好,也越占用CPU時間,后面會有詳細(xì)說明
- gzip_comp_level 2;
- # 進(jìn)行壓縮的文件類型。javascript有多種形式。其中的值可以在 mime.types 文件中找到。
- gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
應(yīng)用構(gòu)建時候壓縮
既然服務(wù)端都可以做了為什么 webpack
在打包前端應(yīng)用時候還有這樣一個壓縮插件呢,我們可以在上面 nginx
配置中看到 gzip_comp_level 2
這個配置項,上面也有注釋寫道 1-10
數(shù)字越大壓縮效果越好,但是會耗費更多的CPU和時間,我們壓縮文件除了減少文件體積大小外,也是為了減少傳輸時間,如果我們把壓縮等級配置的很高,每次請求服務(wù)端都要壓縮很久才回返回信息回來,不僅服務(wù)器開銷會增大很多,請求方也會等的不耐煩。但是現(xiàn)在的 spa
應(yīng)用既然文件都是打包生成的,那如果我們在打包時候就直接生成高壓縮等級的文件,作為靜態(tài)資源放在服務(wù)器上,接收到請求后直接把壓縮的文件內(nèi)容返回回去會怎么樣呢?
webpack
的 compression-webpack-plugin
就是做這個事情的,配置起來也很簡單只需要在裝置中加入對應(yīng)插件,簡單配置如下
- 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
后綴的壓縮文件
那么這個插件的壓縮等級是多少呢,我們可以在源碼中看到默認(rèn)的 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
分級來說,默認(rèn)是 6 ,最高的級別就是9 Best compression (also zlib.Z_BEST_COMPRESSION)
,因為我們只有在上線項目時候才回去打包構(gòu)建一次,所以我們在構(gòu)建時候使用最高級的壓縮方式壓縮多耗費一些時間對我們來說根本沒任何損耗,而我們在服務(wù)器上也不用再去壓縮文件,只需要找到相應(yīng)已經(jīng)壓縮過的文件直接返回就可以了。
服務(wù)端怎么找到這些文件
在應(yīng)用層面解決這個問題還是比較簡單的,比如上述壓縮文件會產(chǎn)生index.css
, index.js
的壓縮文件,在服務(wù)端簡單處理可以判斷這兩個請求然后給予相對應(yīng)的壓縮文件。以 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)) // 這里要根據(jù)請求文件設(shè)置content-type
- next()
- })
上面我們可以給請求返回 gZip
壓縮后的數(shù)據(jù)了,當(dāng)然上面的局限性太強(qiáng)也不可取,但是對于處理這個方面需求也已經(jīng)有很多庫存在,express
有 express-static-gzip 插件 koa
的 koa-static
則默認(rèn)自帶對 gZip
文件的檢測,基本原理就是對請求先檢測 .gz
后綴的文件是否存在,再去根據(jù)結(jié)果返回不同的內(nèi)容。
哪些文件可以被 gZip 壓縮
gZip
可以壓縮所有的文件,但是這不代表我們要對所有文件進(jìn)行壓縮,我們寫的代碼(css,js
)之類的文件會有很好的壓縮效果,但是圖片之類文件則不會被 gzip
壓縮太多,因為它們已經(jīng)內(nèi)置了一些壓縮,一些文件(比如一些已經(jīng)被壓縮的像.zip文件那種)再去壓縮可能會讓生成的文件體積更大一些。當(dāng)然已經(jīng)很小的文件也沒有去壓縮的必要了。
實踐
能開啟 gZip
肯定是要開啟的,具體使用在請求時候?qū)崟r壓縮還是在構(gòu)建時候去生成壓縮文件,就要看自己具體業(yè)務(wù)情況。