前言
網(wǎng)頁(yè)加載速度加快的好處不言而喻,除了節(jié)省流量,改善用戶的瀏覽體驗(yàn)外,另一個(gè)潛在的好處是Gzip與搜索引擎的抓取工具有著更好的關(guān)系。例如 Google就可以通過(guò)直接讀取gzip文件來(lái)比普通手工抓取更快地檢索網(wǎng)頁(yè)。在Google網(wǎng)站管理員工具(Google Webmaster Tools)中你可以看到,sitemap.xml.gz 是直接作為Sitemap被提交的。
而這些好處并不僅僅限于靜態(tài)內(nèi)容,PHP動(dòng)態(tài)頁(yè)面和其他動(dòng)態(tài)生成的內(nèi)容均可以通過(guò)使用Apache壓縮模塊壓縮,加上其他的性能調(diào)整機(jī)制和相應(yīng)的服務(wù)器端 緩存規(guī)則,這可以大大提高網(wǎng)站的性能。因此,對(duì)于部署在Linux服務(wù)器上的PHP程序,在服務(wù)器支持的情況下,我們建議你開(kāi)啟使用Gzip Web壓縮。下面來(lái)一起看看詳細(xì)的介紹吧。
為什么要開(kāi)啟gZip
我們給某人發(fā)送郵件時(shí),我們?cè)趥鬏斨鞍炎约旱奈募嚎s一下,接收方收到文件后再去解壓獲取文件。這中操作對(duì)于我們來(lái)說(shuō)都已經(jīng)司空見(jiàn)慣。我們壓縮文件的目的就是為了把傳輸文件的體積減小,加快傳輸速度。我們?cè)?http 傳輸中開(kāi)啟 gZip 的目的也是如此,但是一般文章介紹 gZip 時(shí)候總是結(jié)合一些服務(wù)端配置(nginx)或者構(gòu)建工具插件(webpack)來(lái)說(shuō),列出一大堆配置讓人看的云里霧里,以至于到最后還沒(méi)搞懂 為什么用,怎么用 這些問(wèn)題。
http 與 gZip
我們下面去探討一下這些問(wèn)題
gZip 文件怎么通訊
我們傳輸壓縮文件給別人時(shí)候一般都帶著后綴名 .rar, .zip之類,對(duì)方在拿到文件后根據(jù)相應(yīng)的后綴名選擇不同的解壓方式然后去解壓文件。我們?cè)?http 傳輸時(shí)候解壓文件的這個(gè)角色的扮演者就是我們使用的瀏覽器,但是瀏覽器怎么分辨這個(gè)文件是什么格式,應(yīng)該用什么格式去解壓呢?
在 http/1.0 協(xié)議中關(guān)于服務(wù)端發(fā)送的數(shù)據(jù)可以配置一個(gè) Content-Encoding 字段,這個(gè)字段用于說(shuō)明數(shù)據(jù)的壓縮方法
Content-Encoding: gzip Content-Encoding: compress Content-Encoding: deflate
客戶端在接受到返回的數(shù)據(jù)后去檢查對(duì)應(yīng)字段的信息,然后根據(jù)對(duì)應(yīng)的格式去做相應(yīng)的解碼??蛻舳嗽谡?qǐng)求時(shí),可以用 Accept-Encoding 字段說(shuō)明自己接受哪些壓縮方法。
Accept-Encoding: gzip, deflate
我們?cè)跒g覽器的控制臺(tái)中可以看到請(qǐng)求的相關(guān)信息
兼容性
提到瀏覽器作為一個(gè)前端就不由自主的會(huì)想一個(gè)問(wèn)題,會(huì)不會(huì)有瀏覽器不支持呢。HTTP/1.0 是1996年5月發(fā)布的。好消息是基本不用考慮兼容性的問(wèn)題,幾乎所有瀏覽器都支持它。值得一提的是 ie6的早起版本中存在一個(gè)會(huì)破壞 gZip的錯(cuò)誤,后面 ie6本身在 WinXP SP2 中修復(fù)了這個(gè)問(wèn)題,而且用這個(gè)版本的用戶數(shù)量也很少。
誰(shuí)去壓縮文件
這件事看起來(lái)貌似只能服務(wù)端來(lái)做,我們?cè)诰W(wǎng)上看到最多的也是諸如 nginx 開(kāi)啟 gZip 配置之類的文章,但是現(xiàn)在前端流行 spa 應(yīng)用, 用 react, vue 之類的框架時(shí)候總伴隨這一套自己的腳手架,一般用 webpack 作為打包工具,其中可以配置插件 如compression-webpack-plugin 可以讓我們把生成文件進(jìn)行 gZip 等壓縮并生成對(duì)應(yīng)的壓縮文件,而我們應(yīng)用在構(gòu)架時(shí)候有可能也會(huì)在服務(wù)區(qū)和前端文件中放置一層 node 應(yīng)用來(lái)進(jìn)行接口鑒權(quán)和文件轉(zhuǎn)發(fā)。nodejs中我們熟悉的express 框架中也有一個(gè)compression 中間件,可以開(kāi)啟gZip,一時(shí)間看的人眼花繚亂,到底應(yīng)該用誰(shuí)怎么用呢?
服務(wù)端響應(yīng)請(qǐng)求時(shí)候壓縮
其實(shí) nginx 壓縮和 node 框架中用中間件去壓縮都是一樣的,當(dāng)我們點(diǎn)擊網(wǎng)頁(yè)發(fā)送一個(gè)請(qǐng)求時(shí)候,我們的服務(wù)端會(huì)找到對(duì)應(yīng)的文件,然后對(duì)文件進(jìn)行壓縮返回壓縮后的內(nèi)容【當(dāng)然可以利用緩存減少壓縮次數(shù)】,并配置好我們上面提到的 Content-Encoding 信息。對(duì)于一些應(yīng)用在構(gòu)架時(shí)候并沒(méi)有上游代理層,比如服務(wù)端就一層 node 就可以直接用自己本身的壓縮插件對(duì)文件進(jìn)行壓縮,如果上游配有有 nginx 轉(zhuǎn)發(fā)處理層,最好交給 nginx 來(lái)處理這些,因?yàn)樗鼈冇袑iT為此構(gòu)建的內(nèi)容,可以更好的利用緩存并減小開(kāi)銷(很多使用c語(yǔ)言編寫的)。
我們看一些 nginx 中開(kāi)啟 gZip 壓縮的一部分配置
# 開(kāi)啟gzip gzip on; # 啟用gzip壓縮的最小文件,小于設(shè)置值的文件將不會(huì)壓縮 gzip_min_length 1k; # gzip 壓縮級(jí)別,1-10,數(shù)字越大壓縮的越好,也越占用CPU時(shí)間,后面會(huì)有詳細(xì)說(shuō)明 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)建時(shí)候壓縮
既然服務(wù)端都可以做了為什么 webpack 在打包前端應(yīng)用時(shí)候還有這樣一個(gè)壓縮插件呢,我們可以在上面 nginx 配置中看到 gzip_comp_level 2 這個(gè)配置項(xiàng),上面也有注釋寫道 1-10 數(shù)字越大壓縮效果越好,但是會(huì)耗費(fèi)更多的CPU和時(shí)間,我們壓縮文件除了減少文件體積大小外,也是為了減少傳輸時(shí)間,如果我們把壓縮等級(jí)配置的很高,每次請(qǐng)求服務(wù)端都要壓縮很久才回返回信息回來(lái),不僅服務(wù)器開(kāi)銷會(huì)增大很多,請(qǐng)求方也會(huì)等的不耐煩。但是現(xiàn)在的 spa 應(yīng)用既然文件都是打包生成的,那如果我們?cè)诖虬鼤r(shí)候就直接生成高壓縮等級(jí)的文件,作為靜態(tài)資源放在服務(wù)器上,接收到請(qǐng)求后直接把壓縮的文件內(nèi)容返回回去會(huì)怎么樣呢?
webpack 的 compression-webpack-plugin 就是做這個(gè)事情的,配置起來(lái)也很簡(jiǎn)單只需要在裝置中加入對(duì)應(yīng)插件,簡(jiǎn)單配置如下
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 打包完成后生成打包文件外還會(huì)額外生成 .gz 后綴的壓縮文件
那么這個(gè)插件的壓縮等級(jí)是多少呢,我們可以在源碼中看到默認(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 庫(kù),而 zlib 分級(jí)來(lái)說(shuō),默認(rèn)是 6 ,最高的級(jí)別就是9 Best compression (also zlib.Z_BEST_COMPRESSION),因?yàn)槲覀冎挥性谏暇€項(xiàng)目時(shí)候才回去打包構(gòu)建一次,所以我們?cè)跇?gòu)建時(shí)候使用最高級(jí)的壓縮方式壓縮多耗費(fèi)一些時(shí)間對(duì)我們來(lái)說(shuō)根本沒(méi)任何損耗,而我們?cè)诜?wù)器上也不用再去壓縮文件,只需要找到相應(yīng)已經(jīng)壓縮過(guò)的文件直接返回就可以了。
服務(wù)端怎么找到這些文件
在應(yīng)用層面解決這個(gè)問(wèn)題還是比較簡(jiǎn)單的,比如上述壓縮文件會(huì)產(chǎn)生index.css, index.js的壓縮文件,在服務(wù)端簡(jiǎn)單處理可以判斷這兩個(gè)請(qǐng)求然后給予相對(duì)應(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ù)請(qǐng)求文件設(shè)置content-type next() })
上面我們可以給請(qǐng)求返回 gZip 壓縮后的數(shù)據(jù)了,當(dāng)然上面的局限性太強(qiáng)也不可取,但是對(duì)于處理這個(gè)方面需求也已經(jīng)有很多庫(kù)存在,express 有 express-static-gzip 插件 koa 的 koa-static 則默認(rèn)自帶對(duì) gZip 文件的檢測(cè),基本原理就是對(duì)請(qǐng)求先檢測(cè) .gz后綴的文件是否存在,再去根據(jù)結(jié)果返回不同的內(nèi)容。
哪些文件可以被 gZip 壓縮
gZip 可以壓縮所有的文件,但是這不代表我們要對(duì)所有文件進(jìn)行壓縮,我們寫的代碼(css,js)之類的文件會(huì)有很好的壓縮效果,但是圖片之類文件則不會(huì)被 gzip 壓縮太多,因?yàn)樗鼈円呀?jīng)內(nèi)置了一些壓縮,一些文件(比如一些已經(jīng)被壓縮的像.zip文件那種)再去壓縮可能會(huì)讓生成的文件體積更大一些。當(dāng)然已經(jīng)很小的文件也沒(méi)有去壓縮的必要了。
實(shí)踐
能開(kāi)啟 gZip 肯定是要開(kāi)啟的,具體使用在請(qǐng)求時(shí)候?qū)崟r(shí)壓縮還是在構(gòu)建時(shí)候去生成壓縮文件,就要看自己具體業(yè)務(wù)情況。
參考資料
總結(jié)
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com