日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

gzip壓縮簡介

什么是gzip壓縮,gzip壓縮是基于deflate中的算法進行壓縮的,gzip會產生自己的數據格式,gzip壓縮對于所需要壓縮的文件,首先使用LZ77算法進行壓縮,再對得到的結果進行huffman編碼,根據實際情況判斷是要用動態huffman編碼還是靜態huffman編碼,最后生成相應的gz壓縮文件。

gzip和deflate的區別

大家可能注意到了,在我們的HTTP請求頭中,會存在accept-encoding字段,其實就是在告訴服務器,客戶端所能接受的文件的壓縮格式,其中包括gzip、deflate和br等。

那么常見的gzip和deflate有什么區別呢?

1、GZIP,好像是一個不透明的或原子的功能。事實上,HTTP定義了一種機制,一個Web客戶機和Web服務器同意一壓縮方案可以用來發送內容,這由使用Accept-Encoding和Content-Encoding標頭完成。有兩種常用的HTTP壓縮:DEFLATE和GZIP。

2、DEFLATE是一個無專利的壓縮算法,它可以實現無損數據壓縮,有眾多開源的實現算法。該標準的實施庫大多數人用的是zlib的。zlib庫提供用于壓縮和解壓縮使用DEFLATE/INFLATE的數據。zlib庫還提供了一種數據格式,混淆的命名ZLIB,它包裝DEFLATE壓縮數據,具有報頭和校驗和。

總而言之,GZIP是使用DEFLATE進行壓縮數據的另一個壓縮庫。事實上,GZIP的大多數實現實際使用zlib庫的內部進行DEFLATE/ INFLATE壓縮操作。GZIP產生其自己的數據格式,混淆的命名GZIP,它包裝DEFLATE壓縮數據,具有報頭和校驗和。而由于最初的規定不統一問題,大多數情況下已經啟用deflate壓縮。

gzip壓縮原理

接下來進入本文的正題之一,gzip壓縮的流程是怎么樣的?

其實gzip壓縮一般都是針對文本文件進行壓縮,至于原因后面會介紹到,首先LZ77算法基于文本文件對文本內容,即文件中的字符串進行首次壓縮,接下來,利用哈夫曼編碼,轉換為010111..等2進制進行存儲。那么具體的算法是怎樣的呢?

1、LZ77算法

LZ77算法的核心思想,是對字符串的重復利用,在掃描整個文本的過程中,判斷之前的字符串中,有沒有出現過類似的字符串或子字符串,通過這樣的方式來壓縮你的文本長度,舉個簡單的栗子:

文本內容如下:

http://www.qq.com

http://www.paipai.com

我們把相同的內容括起來

http://www.qq.com

http://www.)paipai(.com)

用信息對替換之后的結果是

http://www.qq.com

(18,11)paipai(22,4)

其中

(18,11)中,18(起點到下一個起點,包含換行)為相同內容塊與當前位置之間的距離,11為相同內容的長度。

(22,4)中,22為相同內容塊與當前位置之間的距離,4為相同內容的長度。

由于信息對的大小,小于被替換內容的大小,所以文件得到了壓縮。

算法具體實現,首先你要明確幾個名詞概念:

1.前向緩沖區

每次讀取數據的時候,先把一部分數據預載入前向緩沖區。為移入滑動窗口做準備

2.滑動窗口

一旦數據通過緩沖區,那么它將移動到滑動窗口中,并變成字典的一部分。

3.短語字典

從字符序列S1...Sn,組成n個短語。比如字符(A,B,D) ,可以組合的短語為{(A),(A,B),(A,B,D),(B),(B,D),(D)},如果這些字符在滑動窗口里面,就可以記為當前的短語字典,因為滑動窗口不斷的向前滑動,所以短語字典也是不斷的變化。

在遍歷整個文本的字符串的過程中,算法通過判斷前向緩沖區中,是否存在滑動窗口中的最長子字符串,實現字符串的“復用”,具體可以看下圖:

HTTP請求之gzip壓縮知多少

 

目前滑動窗口中存在的字符串,除去單字符的,則有AB、BD、ABD,而前向緩沖區中,存在AB、ABC、BC,最長的子字符串為AB,則可以將ABC壓縮為(0,2,C),其中0表示在滑動窗口中的偏移量,2表示讀取兩個字符,C表示未匹配的字符。接下來我們看一個完整的壓縮案例你就懂了:(圖片引自: https://www.jb51.net/article/... )

HTTP請求之gzip壓縮知多少

 

那么解壓過程呢?其實解壓過程是非常快速的,如下:

HTTP請求之gzip壓縮知多少

 

可以看出,LZ77算法的耗時,主要在于壓縮階段中,判斷前向緩沖區和滑動窗口中的最長字符串匹配,也就是說,選擇滑動窗口大小,以及前向緩沖區大小,對你的LZ77算法的時間復雜度有著關鍵的影響,其次,合適的滑動窗口大小、緩沖區大小能幫助你對文件進行更好的壓縮,提高壓縮率。

而在整個解壓的過程,只需要通過簡單的字符讀取,根據偏移量復用子字符串,就完成了解壓過程,整個過程沒有復雜的算法耗時,這也正符合了我們在網絡請求中的適用場景,通過在服務端對文件的一次壓縮,提供給所有的用戶使用,在客戶端對數據進行解壓,而解壓基本沒有什么耗時,因此能大大提高我們的頁面資源加載速度。

2、huffman編碼

當你對文件中的文本進行壓縮后,接下來其實就是文本的存儲了,ASCII編碼中,一個字符對應一個字節,通過8位來表示,但是我們真的不能在優化了嗎?huffman編碼告訴我們,我們還能再壓縮!huffman的原理,本質是通過判斷字符在文本中的出現頻次,規定每個字符的編碼,而非固定8位編碼,舉個簡單的栗子:

字符串:AAABCB

按照以往的存儲方式 需要6個字節,48bits。

但是我們可以看到,A出現了3次,B出現了2次,C僅僅出現了1次,于是我們換一種存儲方式,

用0來表示A,10來表示B,11來表示C

最后的壓縮結果是000101110 ,最后我們只用了9個bits來存儲了這個字符串!

這就是huffman的根本原理。

可以看到我們的關鍵在于,為字符生成相應的編碼,所以這個過程需要我們構造一個哈弗曼樹,什么是哈夫曼樹呢?哈弗曼樹是通過一系列值,將這些值作為葉子節點,注意是葉子節點,構造成一個樹,這個樹要求,( 葉子節點的權重 葉子節點的深度 ) 所有葉子節點總數n 的值達到最小。具體的構造過程如下:(圖片引自 http://www.360doc.com/content... )

HTTP請求之gzip壓縮知多少

 

其中,節點值表示字符出現的頻次,葉子節點的層級變相意味著 字符編碼的長度,其實這也很好理解,我們希望出現頻次越多的字符,編碼越短越好,頻次較少的字符,編碼長度較長也無所謂。這也和哈夫曼樹的定義完美契合。

可以看到字符串:

abbbbccccddde

a b c d e

1 4 4 3 1

經過我們的huffman編碼后,分別表示如下:

a 為 110

b 為 00

c 為 01

d 為 10

e 為 111

聰明的你可能還留意到了,通過huffman編碼后的二進制字符,是沒有二義性的。

可以看到我們上述的案例,動態生成了huffman編碼,所以最后傳輸數據的時候,還需要把huffman樹的信息一起傳遞過去,當然,這里還存在 靜態huffman和動態huffman的區別 :

靜態Huffman編碼就是使用gzip自己預先定義好了一套編碼進行壓縮,解壓縮的時候也使用這套編碼,這樣不需要傳遞用來生成樹的信息。

動態Huffman編碼就是使用統計好的各個符號的出現次數,建立Huffman樹,產生各個符號的Huffman編碼,用這產生的Huffman編碼進行壓縮,這樣需要傳遞生成樹的信息。

Gzip 在為一塊進行Huffman編碼之前,會同時建立靜態Huffman樹,和動態Huffman樹,然后根據要輸出的內容和生成的Huffman樹,計算使用靜態Huffman樹編碼,生成的塊的大小,以及計算使用動態Huffman樹編碼,生成塊的大小。然后進行比較,使用生成塊較小的方法進行Huffman編碼。

對于靜態樹來說,不需要傳遞用來生成樹的那部分信息。動態樹需要傳遞這個信息。而當文件比較小的時候,傳遞生成樹的信息得不償失,反而會使壓縮文件變大。也就是說對于文件比較小的時候,就可能會出現使用靜態Huffman編碼比使用動態Huffman編碼,

生成的塊小。

如何開啟gzip

竟然gzip這么棒,趕緊在我們的項目中用起來吧!

express和koa默認都沒有開啟gzip壓縮,所以需要自行引入中間件的形式開啟壓縮,針對text文件進行文本壓縮。

const Koa = require("koa");
const path = require("path")
var compress = require('koa-compress')
const App = new Koa();

const static = require('koa-static')


app.use(compress({
  filter: function (content_type) {
   return /text/g.test(content_type)
  },
  threshold: 1,
  flush: require('zlib').Z_SYNC_FLUSH
}))

app.use(async(ctx, next) => {
  //ctx 代表響應 ctx.compress = trus 代表允許壓縮
  // ctx.compress = true
  // ctx.body = "hello"
  await next()
})


app.use(static(
  path.join( __dirname, 'public'),{
    gzip:true
  }
))
//可以配置一個或多個
// app.use(static(__dirname + '/static')))

app.listen(3000);

需要注意 koa 的中間件使用 和express是不一樣的。

其次,通過filter 函數來判斷是否要進行gzip壓縮。

除了Nginx或server層做gzip壓縮。

也可以在構建的時候壓縮,生成相應的gz文件。

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
    })
)

關于gzip的Q & A

Q:gzip是否僅限制于文本文件,對于二進制文件呢?音頻?圖片等資源呢?

A:gzip壓縮不僅適用于文本文件,其實也可以對圖片等二進制文件進行壓縮,但是不推薦這么做,由于gzip的壓縮過程首先基于字符串進行LZ77處理,接下里再通過huffman編碼,然而,大多數的二進制文件,已經有自己的編碼和壓縮方式了,對二進制文件進行在壓縮,可能導致文件更大,同時,會增大客戶端解壓縮的壓力,帶來不必要的CPU損耗。

一些開發者使用HTTP壓縮那些已經本地已經壓縮過的文件,而這些已經壓縮過的文件再次被GZip壓縮時,是不能提高性能的,表現在如下兩個方面。

首先,HTTP壓縮需要成本。Web服務器獲得需要的內容,然后壓縮它,最后將它發送到客戶端。如果內容不能被進一步壓縮,你只是在浪費CPU做無意義的任務。

其次,采用HTTP壓縮已經被過壓縮的東西并不能使它更小。事實上,添加標頭,壓縮字典,并校驗響應體實際上使它變得更大,如下圖所示:

HTTP請求之gzip壓縮知多少

 

Q:gzip壓縮過得文件,可以再進行一次gzip壓縮嗎?多次呢?

A:可以進行再壓縮,但是gzip首次壓縮過后的文件,本身已經是二進制文件,對文件進行再壓縮只會帶來沒必要的性能損耗,同時可能導致文件增大。

Q:需要對所有文本內容都進行GZIP壓縮嗎?

A:答案是否定的,可以看到我們的壓縮過程中,需要執行算法,假如傳輸的字符串僅僅幾十個字符,那么執行算法是完全沒有必要的,并且,對過短的字符進行壓縮,可能反而導致傳輸數據量增大,例如可能要傳輸動態構造的huffman樹信息等。

Q:在哪個階段對文件進行gzip壓縮比較合適?

A:在本地構建部署的時候,通過webpack生成最終的gz壓縮文件部署上服務器,是最高效的,假如通過引入中間件,在請求到來時再對文本文件進行壓縮,只會讓用戶的等待時間更長,所以筆者認為,在webpack打包構建的時候做這件事是最合理的。

分享到:
標簽:壓縮 gzip
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定