天天看點

用了這麼久HTTP, 你是否了解Content-Length?

摘要: 了解HTTP協定...

由Content-Length導緻的問題引發的一系列思考:

前段時間開發API網關, 使用postman調試時出現了逾時的情況, 經排查确定是請求資料被處理後

Content-Length

與實際不一緻導緻的問題, 故有此文.

Content-Length

, HTTP消息長度, 用十進制數字表示的八位位元組的數目. 一般情況下, 很多工作都被架構完成, 我們很少去關注這部分内容, 但少數情況下發生了

Content-Length

與實際消息長度不一緻, 程式可能會發生比較奇怪的異常, 如:

  • 無響應直到逾時.
  • 請求被截斷, 而且下一個請求解析出現錯亂.

Content-Length

是HTTP消息長度, 用十進制數字表示的八位位元組的數目, 是Headers中常見的一個字段.

Content-Length

應該是精确的, 否則就會導緻異常 (特别地, HTTP1.0中這個字段可有可無).

Content-Length

首部訓示出封包中實體主體的位元組大小. 這個大小是包含了所有内容編碼的, 比如, 對文本檔案進行了

gzip

壓縮的話,

Content-Length

首部指的就是壓縮後的大小而不是原始大小.

Content-Length是如何工作的

Content-Length

使用十進制的數字表示了消息的長度, 服務端/用戶端通過它來得知後續要讀取消息的長度.

用了這麼久HTTP, 你是否了解Content-Length?
用了這麼久HTTP, 你是否了解Content-Length?

如果這個長度不正确, 會發生如下情況:

Content-Length > 實際長度

如果Content-Length比實際的長度大, 服務端/用戶端讀取到消息結尾後, 會等待下一個位元組, 自然會無響應直到逾時.

用了這麼久HTTP, 你是否了解Content-Length?

同樣地, 在響應消息中

Content-Length

超過實際長度也是一樣的效果:

用了這麼久HTTP, 你是否了解Content-Length?
用了這麼久HTTP, 你是否了解Content-Length?

Content-Length < 實際長度

如果這個長度小于實際長度, 首次請求的消息會被截取, 比如參數為

param=piaoruiqing

,

Content-Length

為10, 那麼這次請求的消息會被截取為:

param=piao

, 如圖所示:

用了這麼久HTTP, 你是否了解Content-Length?
用了這麼久HTTP, 你是否了解Content-Length?

但, 僅僅是如此嗎, 當然不, 我們再來看看第二次請求會發生什麼讓人意外的事情, 如圖:

用了這麼久HTTP, 你是否了解Content-Length?

連續的兩次請求, 第一次消息被截斷, 而第二次沒有發生預期的截斷, 而是服務端抛出了異常:

Request method 'ruiqingPOST' not supported

.刺不刺激 (ノ)゚Д゚( )

ruiqingPOST

是個什麼神仙方法??? 此時, 憑着多年開發(DEBUG)經驗練就的敏感度, 我們大緻可以猜出, 上一次請求被截取剩下的消息, 在這次請求出現了. 掏出wireshark來驗證一下, 如圖:

用了這麼久HTTP, 你是否了解Content-Length?

導緻這種情況的原因就是開啟了

Connection:keep-alive

, 如果使用

Connection:close

, 所産生的現象就是每一次的請求都被截斷, 但不會産生解析混亂(如将上一次剩下的消息拼接到後續的請求消息中).

不确定Content-Length的值怎麼辦

Content-Length

首部訓示出封包中實體主體的位元組大小. 但如在請求處理完成前無法擷取消息長度, 我們就無法明确指定

, 此時應該使用

Transfer-Encoding: chunked

什麼是Transfer-Encoding: chunked

資料以一系列分塊的形式進行發送.

Content-Length

首部在這種情況下不被發送. 在每一個分塊的開頭需要添加目前分塊的長度, 以十六進制的形式表示,後面緊跟着

\r\n

, 之後是分塊本身, 後面也是

\r\n

. 終止塊是一個正常的分塊, 不同之處在于其長度為0.

Transfer-Encoding: chunked是如何工作的

接下來我們用一個下載下傳檔案的例子, 來探讨

Transfer-Encoding: chunked

是如何工作的. 服務端代碼如下:

用了這麼久HTTP, 你是否了解Content-Length?

使用postman發起請求, wireshark抓包檢視, 如圖:

用了這麼久HTTP, 你是否了解Content-Length?

在wireshark中可以很清晰地看到chunked的資料, 其結構大緻是: 傳回的消息被分為多個資料塊, 每個資料塊有兩部分,

長度

+

資料

, 這兩部分都以CRLF(即

\r\n

)結尾. 而終止塊是一個特殊的資料塊, 其長度為0, 如圖:

用了這麼久HTTP, 你是否了解Content-Length?

如此, 即完成了分塊編碼. 其主要應用于如下場景, 即要傳輸大量的資料, 但是在請求在沒有被處理完之前響應的長度是無法獲得的. 例如, 當需要用從資料庫中查詢獲得的資料生成一個大的HTML表格、需要傳輸大量的圖檔等.

  • Content-Length

    如果存在且生效, 必須是正确的, 否則會發生異常.(大于實際值會逾時, 小于實際值會截斷并可能導緻後續的資料解析混亂)
  • 如果封包中包含

    Transfer-Encoding: chunked

    首部, 那麼

    Content-Length

    将被忽略.

參考

版權聲明

本文釋出于

, 允許非商業用途轉載, 但轉載必須保留原作者

樸瑞卿

及連結:

https://blog.piaoruiqing.com

. 如有授權方面的協商或合作, 請聯系郵箱: [email protected].

關于Fundebug

Fundebug

專注于JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了20億+錯誤事件,付費客戶有陽光保險、核桃程式設計、荔枝FM、掌門1對1、微脈、青團社等衆多品牌企業。歡迎大家

免費試用

繼續閱讀