透過HTTP發送大量資料的三種方法

2023.10.13

透過HTTP發送大量資料的三種方法


我們有三種方法可以透過HTTP縮短發送大量資料的時間,它們並不是互斥的。你可以根據用例一起使用所有方法。

在網路的早期時期,人們發送的檔案大小僅為幾KB。到了2023年,我們享受著高解析度的MB級影像,並在幾GB的4K(即將是8K)影片中觀看。

即使有良好的互聯網連接,下載一個5GB的檔案仍然需要一些時間。如果你擁有Xbox或PlayStation,你就知道這種感覺。

我們有三種方法可以透過HTTP縮短發送大量資料的時間:

  • 壓縮數據
  • 發送分塊數據
  • 請求選擇範圍內的數據

它們並不是互斥的。你可以根據用例一起使用所有方法。

壓縮數據

1*_un0bHBemgCSDocQmucK5Q.png

要壓縮數據,我們需要壓縮演算法。

在發送請求時,瀏覽器會包含一個名為Accept-Encoding的頭,其中包含支援的壓縮演算法列表,包括gzip(GZIP)、compress、deflate和br(Brotli)。

接下來,伺服器從清單中選擇其支援的演算法,並在Content-Encoding頭中設定演算法名稱。

當瀏覽器接收到回應時,它知道如何解析正文中的資料。

在這些演算法中,最受歡迎的是GZIP。它是壓縮文字資料(如HTML、CSS和JavaScript)的絕佳選擇。

Brotli是另一個值得一提的演算法。它在壓縮HTML方面的效能甚至比GZIP更好。

這些高效的演算法有一些限制。

它們對文字的壓縮效果很好,但對於壓縮圖像或影片來說則不足夠。畢竟,媒體已經過了優化。

試著在你的電腦上壓縮一個視訊檔案。在壓縮之前和之後,你幾乎看不到太大的差別。

此外,幾乎不可能將一個5GB的視訊壓縮到幾KB而不損失品質。

壓縮是好的,但我們需要一個更好的解決方案——將檔案分塊發送並在客戶端組裝部分資料。

發送分塊數據

1*0WLNkzfgw9faLpTUXkk3tg.png

在版本1.1中,HTTP引入了分塊資料以處理大數據情況。

在傳送回應時,伺服器會新增一個頭Transfer-Encoding: chunked,讓瀏覽器知道資料是分塊傳送的。

1*Nwlp0QqhEsvWl4fw-x0X7Q.png

每個分塊資料都有以下組件:

  • 一個長度塊標記,標記目前分塊資料的長度
  • 分塊資料塊
  • 在每個區塊的末尾的CRLF分隔符

想知道CRLF是什麼嗎?

1*s_-5lmT9176ymCAaaGCE2w.png

CR緊接著LF(CRLF,\r\n,或0x0D0A)將遊標移到下一行,然後移到行的開頭。在本文末尾的進一步閱讀部分,你可以找到更多詳細資訊。在這裡,你可以簡單地將其視為分隔符號。

伺服器繼續向瀏覽器串流傳輸分塊資料。當達到資料流的末端時,它會附加一個包含以下部分的結束標記:

  • 一個長度塊,數字為0,末尾為CRLF
  • 一個額外的CRLF

在瀏覽器端,它等待所有資料塊,直到達到結束標記。然後,它移除分塊編碼,包括CRLF和長度資訊。

接下來,它將分塊資料組合成一個整體。因此,在Chrome DevTools上,你只能看到組裝後的數據,而不是分塊數據。

最終,你會收到整個數據的一塊。

1*oChWIlysG3PQD3vy8ctVxw.png

分塊資料是有用的。然而,對於一個5GB的視頻,完整的數據仍然需要一些時間才能到達。

我們能不能取得資料的選定區塊,並在需要時請求其他區塊呢?

HTTP說可以。

在選定範圍內請求數據

1*LOGONes_KpmSN6zXaz9DhA.png

在YouTube上打開一個視頻,你會看到一個灰色的進度條正在向前移動。

你剛剛看到的是YouTube在請求選定範圍內的資料。

此功能使你可以在時間軸的任何地方跳躍。當點擊進度條上的某個位置時,瀏覽器會要求影片資料的特定範圍。

在伺服器上實現範圍請求是可選的。如果實作了,你可以在回應頭中看到Accept-Ranges: bytes。

1*MWd4AGP8lLRIQw5mketXew.png

這是一個YouTube請求的範例。在任何「playback」請求中,你都可以找到這個頭。

範圍請求頭看起來像`Range:bytes=0-80`,它是從0開始的索引。

這個頭是一個設計非常巧妙且具有出色靈活性的頭。

假設一個資料總共有100個位元組。

  • Range: bytes=20請求從20開始到最後的範圍,等於Range: bytes=20-99。
  • Range: bytes=-20請求資料的最後20個字節,等於Range: bytes=80-99。

如果請求的範圍有效,伺服器將發送帶有Content-Range頭的回應,驗證資料範圍和總長度,例如Content-Range: bytes 70-80/100。

範圍請求廣泛用於視訊串流媒體和文件下載服務。

你有沒有在網路中斷後繼續文件下載?那就是範圍請求。

此外,範圍請求支援多個範圍。

例如,你可以從文件中要求兩個範圍,如Range: bytes=20-45, 70-80。

多範圍體看起來類似分塊資料。每個資料塊都有以下部分:

  • 一個邊界區塊,標識不同資料塊的邊界,以--開始,以CRLF結束
  • 兩個頭,Content-Type和Content-Range,顯示對應資料區塊的屬性,以CRLF結束
  • 一個額外的CRLF,告訴客戶端真正的資料即將到來
  • 最後,以CRLF結束的資料塊

邊界只是一個看起來像3d6b6a416f9b5的隨機字串,標記不同資料塊的邊界。

最終,體結束於邊界塊,以--開始,以--和CRLF結束。這個部分告訴瀏覽器多部分已經結束。

讓我們把它全部整合起來。響應體的結構如下圖所示。

總結

HTTP幫助我們透過壓縮、分塊資料和範圍資料傳送大量資料。

這裡的想法是在需要的時候傳送我們需要的數據,然後在需要時發送其他數據。當在設計類似系統時遇到問題時,你可以嘗試相同的思路。

透過結合這三種方法,我們可以發送壓縮的分塊資料範圍資料。