壓縮字典傳輸

實驗性: 這是一項實驗性技術
在生產中使用此技術之前,請仔細檢查瀏覽器相容性表格

壓縮字典傳輸是一種利用共享壓縮字典來大幅減小 HTTP 響應傳輸大小的方法。

概述

HTTP 中使用壓縮演算法來減小透過網路下載的資源的大小,從而降低頻寬成本和頁面載入時間。無損 HTTP 壓縮演算法透過查詢源中的冗餘來工作:例如,像字串 "function" 這樣的文字重複出現的地方。然後,它們只包含一份冗餘字串的副本,並用對該副本的引用替換資源中出現的所有冗餘字串。由於引用比字串短,因此壓縮版本更短。

注意:這項技術之前的一次嘗試名為 SDCH (Shared Dictionary Compression for HTTP),但從未得到廣泛支援,並於 2017 年被移除。壓縮字典傳輸是規範更完善、實現更健壯,並具有更廣泛行業共識的實現。

例如,考慮以下 JavaScript

js
function a() {
  console.log("Hello World!");
}

function b() {
  console.log("I am here");
}

這可以透過將重複的字串替換為對先前位置和字元數的引用來壓縮,如下所示

function a() {
  console.log("Hello World!");
}

[0:9]b[10:20]I am here[42:46]

在此示例中,[0:9] 指的是複製從字元 0 開始的 9 個字元。請注意,這是一個簡化示例,旨在演示概念,實際演算法比這更復雜。

客戶端下載後可以反轉壓縮以重新建立原始的未壓縮資源。

壓縮字典

Brotli 壓縮Zstandard 壓縮 這樣的演算法透過允許使用常用字串字典來提高效率,因此您無需在壓縮資源中包含它們的任何副本。這些演算法附帶一個預定義的預設字典,用於壓縮 HTTP 響應時。

壓縮字典傳輸在此基礎上,允許您提供自己的字典,這特別適用於特定的資源集。壓縮演算法在壓縮和解壓縮資源時可以將其作為位元組源進行引用。

假設上一個示例中的引用包含在該公共字典中,這可以進一步減少為

[d0:9]a[d10:20]Hello World![d42:46]
[d0:9]b[d10:20]I am here[d42:46]

字典可以是一個獨立的資源,僅用於壓縮字典傳輸,也可以是網站本來就需要的一個資源。

例如,假設您的網站使用 JavaScript 庫。您通常會載入特定版本的庫,並且可能會在庫名稱中包含版本名稱,例如 <script src="my-library.v1.js">。當瀏覽器載入您的頁面時,它將作為子資源獲取庫的副本。

如果您隨後更新到庫的 v2 版本,庫的大部分程式碼可能保持不變。因此,網站可以透過告訴瀏覽器使用 my-library.v1.js 作為 my-library.v2.js 的壓縮字典,從而大大減小 my-library.v2.js 的下載大小。這樣,v1 和 v2 之間所有相同的字串都不需要包含在 v2 的下載中,因為瀏覽器已經擁有它們。my-library.v2.js 的大部分下載大小就是兩個版本之間的差異。

壓縮字典傳輸可以比使用預設內建字典的壓縮方案獲得數量級更高的壓縮比:有關一些實際結果,請參閱 壓縮字典傳輸示例

字典格式

壓縮字典不遵循任何特定格式,也沒有特定的 MIME 型別。它們是常規檔案,可用於壓縮具有相似內容的其他檔案。

檔案的先前版本通常包含大量相似內容,這就是它們成為優秀字典的原因。使用檔案的先前版本作為字典允許壓縮演算法有效地引用所有未更改的內容,並僅捕獲新版本中相對較小的差異。這種方法被稱為增量壓縮。

另一種方法是將常用字串(例如您的 HTML 模板)一起列在一個新的 dictionary.txt 檔案中,以便它可以用於壓縮網站上的 HTML 頁面。您可以透過使用專門的工具(例如 Brotli 的字典生成器)進一步最佳化此過程,該工具可將字典縮小到最小大小,同時將重疊最小化。

字典也可以有效地壓縮二進位制格式。例如,WASM 二進位制檔案是大型資源,也可以從增量壓縮中受益。

現有資源作為字典

要將資源用作字典,伺服器應在提供資源的響應中包含 Use-As-Dictionary 標頭

http
Use-As-Dictionary: match="/js/app.*.js"

此標頭的值指示哪些資源可以使用此資源作為字典:在此示例中,這包括所有 URL 與給定 模式 匹配的資源。

當稍後請求與給定模式匹配的資源(例如 app.v2.js)時,請求將在 Available-Dictionary 標頭中包含可用字典的 SHA-256 雜湊值,以及 Accept-Encoding 標頭中的 dcb 和/或 dcz 值(用於分別使用 Brotli 或 ZStandard 進行增量壓縮)

http
Accept-Encoding: gzip, br, zstd, dcb, dcz
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:

然後,伺服器可以響應一個經過適當編碼的響應,其中所選的內容編碼在 Content-Encoding 標頭中給出

http
Content-Encoding: dcb

如果響應是可快取的,則必須包含 Vary 標頭,以防止快取將字典壓縮資源提供給不支援它們的客戶端,或提供使用錯誤字典壓縮的響應

http
Vary: accept-encoding, available-dictionary

還可以在 Use-As-Dictionary 標頭中提供一個可選的 id,以便伺服器在不按雜湊儲存字典的情況下更容易找到字典檔案

http
Use-As-Dictionary: match="/js/app.*.js", id="dictionary-12345"

如果提供了此項,則該值將在未來的請求中透過 Dictionary-ID 標頭髮送

http
Accept-Encoding: gzip, br, zstd, dcb, dcz
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:
Dictionary-ID: "dictionary-12345"

伺服器仍必須檢查 Available-Dictionary 標頭中的雜湊值 — Dictionary-ID 是伺服器識別字典的附加資訊,但不能替代 Available-Dictionary 標頭的必要性。

獨立字典

HTML 文件還可以向瀏覽器提供一個壓縮字典,該字典不是瀏覽器透過 <script> 標籤等元素下載的資源。有兩種方法可以實現這一點

  • 包含一個 <link> 元素,其 rel 屬性設定為 compression-dictionary

    html
    <link rel="compression-dictionary" href="/dictionary.dat" />
    
  • 使用 Link 標頭引用字典

    http
    Link: </dictionary.dat>; rel="compression-dictionary"
    

然後,瀏覽器將在空閒時間下載此字典,並且該響應必須包含 Use-As-Dictionary 標頭

http
Use-As-Dictionary: match="/js/app.*.js"

從這裡開始,當請求匹配的資源時,過程與前面的示例類似。

建立字典壓縮響應

字典壓縮響應可以使用 Brotli 或 ZStandard 演算法,並有兩個額外要求:它們還必須包含一個魔術標頭和嵌入式字典雜湊。

字典壓縮資源可以動態建立,但對於靜態資源,最好在構建時預先建立。當使用先前版本作為字典時,這將需要決定建立多少個增量壓縮版本——只為最新版本,或為最後 X 個版本(X 為某個值)。

給定一個名為 dictionary.text 的字典檔案和一個名為 data.text 的待壓縮檔案,以下 Bash 命令將使用 Brotli 壓縮該檔案,生成一個名為 data.txt.dcb 的壓縮檔案

bash
echo -en '\xffDCB' > data.txt.dcb && \
openssl dgst -sha256 -binary dictionary.txt >> data.txt.dcb && \
brotli --stdout -D dictionary.txt data.txt >> data.txt.dcb

給定相同的輸入檔案,以下 Bash 命令將使用 ZStandard 壓縮該檔案,生成一個名為 data.txt.dcz 的壓縮檔案

bash
echo -en '\x5e\x2a\x4d\x18\x20\x00\x00\x00' > data.txt.dcz && \
openssl dgst -sha256 -binary dictionary.txt >> data.txt.dcz && \
zstd -D dictionary.txt -f -o tmp.zstd data.txt && \
cat tmp.zstd >> data.txt.dcz

請注意,您需要在本地安裝 OpenSSL 以及 Brotli 或 ZStandard。

限制

壓縮演算法存在安全攻擊風險,因此壓縮字典傳輸存在多項限制,其中包括

  • 字典必須與使用字典的資源同源。
  • 字典壓縮資源必須與文件源同源,或遵循 CORS 規則,因此需要使用 crossorigin 屬性請求,並使用適當的 Access-Control-Allow-Origin 標頭提供服務。
  • 字典受常見的 HTTP 快取分割槽限制,因此即使它們下載相同的資源,也不能在不同源之間共享。每個源都需要重新下載字典。

此外,字典本身可能成為跟蹤媒介,因此當停用 Cookie 或啟用其他額外的隱私保護時,瀏覽器可能會限制此功能。

規範

規範
未知規範

瀏覽器相容性

html.elements.link.rel.compression-dictionary

http.headers.Accept-Encoding.dcb

http.headers.Accept-Encoding.dcz

http.headers.Available-Dictionary

http.headers.Content-Encoding.dcb

http.headers.Content-Encoding.dcz

http.headers.Dictionary-ID

http.headers.Use-As-Dictionary

另見