探索HTTP傳輸中gzip壓縮的祕密

爲何要開啓gZip

圖片描述

咱們給某人發送郵件時,咱們在傳輸以前把本身的文件壓縮一下,接收方收到文件後再去解壓獲取文件。這中操做對於咱們來講都已經司空見慣。咱們壓縮文件的目的就是爲了把傳輸文件的體積減少,加快傳輸速度。咱們在 http 傳輸中開啓 gZip 的目的也是如此,可是通常文章介紹 gZip 時候老是結合一些服務端配置(nginx)或者構建工具插件(webpack)來講,列出一大堆配置讓人看的雲裏霧裏,以致於到最後還沒搞懂 爲何用怎麼用 這些問題。javascript

http 與 gZip

咱們下面去探討一下這些問題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 應用既然文件都是打包生成的,那若是咱們在打包時候就直接生成高壓縮等級的文件,做爲靜態資源放在服務器上,接收到請求後直接把壓縮的文件內容返回回去會怎麼樣呢?

webpackcompression-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 後綴的壓縮文件

圖片描述

那麼這個插件的壓縮等級是多少呢,咱們能夠在源碼中看到默認的 level9

...
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的壓縮文件,在服務端簡單處理能夠判斷這兩個請求而後給予相對應的壓縮文件。以 nodeexpress 爲例

...
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 壓縮後的數據了,固然上面的侷限性太強也不可取,可是對於處理這個方面需求也已經有不少庫存在,expressexpress-static-gzip 插件 koakoa-static 則默認自帶對 gZip 文件的檢測,基本原理就是對請求先檢測 .gz後綴的文件是否存在,再去根據結果返回不一樣的內容。

哪些文件能夠被 gZip 壓縮

gZip 能夠壓縮全部的文件,可是這不表明咱們要對全部文件進行壓縮,咱們寫的代碼(css,js)之類的文件會有很好的壓縮效果,可是圖片之類文件則不會被 gzip 壓縮太多,由於它們已經內置了一些壓縮,一些文件(好比一些已經被壓縮的像.zip文件那種)再去壓縮可能會讓生成的文件體積更大一些。固然已經很小的文件也沒有去壓縮的必要了。

實踐

能開啓 gZip 確定是要開啓的,具體使用在請求時候實時壓縮仍是在構建時候去生成壓縮文件,就要看本身具體業務狀況。

參考資料

相關文章
相關標籤/搜索