摘要: 了解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
使用十進制的數字表示了消息的長度, 服務端/用戶端通過它來得知後續要讀取消息的長度.

如果這個長度不正确, 會發生如下情況:
Content-Length > 實際長度
如果Content-Length比實際的長度大, 服務端/用戶端讀取到消息結尾後, 會等待下一個位元組, 自然會無響應直到逾時.
同樣地, 在響應消息中
Content-Length
超過實際長度也是一樣的效果:
Content-Length < 實際長度
如果這個長度小于實際長度, 首次請求的消息會被截取, 比如參數為
param=piaoruiqing
,
Content-Length
為10, 那麼這次請求的消息會被截取為:
param=piao
, 如圖所示:
但, 僅僅是如此嗎, 當然不, 我們再來看看第二次請求會發生什麼讓人意外的事情, 如圖:
連續的兩次請求, 第一次消息被截斷, 而第二次沒有發生預期的截斷, 而是服務端抛出了異常:
Request method 'ruiqingPOST' not supported
.刺不刺激 (ノ)゚Д゚( )
那
ruiqingPOST
是個什麼神仙方法??? 此時, 憑着多年開發(DEBUG)經驗練就的敏感度, 我們大緻可以猜出, 上一次請求被截取剩下的消息, 在這次請求出現了. 掏出wireshark來驗證一下, 如圖:
導緻這種情況的原因就是開啟了
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
是如何工作的. 服務端代碼如下:
使用postman發起請求, wireshark抓包檢視, 如圖:
在wireshark中可以很清晰地看到chunked的資料, 其結構大緻是: 傳回的消息被分為多個資料塊, 每個資料塊有兩部分,
長度
+
資料
, 這兩部分都以CRLF(即
\r\n
)結尾. 而終止塊是一個特殊的資料塊, 其長度為0, 如圖:
如此, 即完成了分塊編碼. 其主要應用于如下場景, 即要傳輸大量的資料, 但是在請求在沒有被處理完之前響應的長度是無法獲得的. 例如, 當需要用從資料庫中查詢獲得的資料生成一個大的HTML表格、需要傳輸大量的圖檔等.
-
如果存在且生效, 必須是正确的, 否則會發生異常.(大于實際值會逾時, 小于實際值會截斷并可能導緻後續的資料解析混亂)Content-Length
- 如果封包中包含
首部, 那麼Transfer-Encoding: chunked
将被忽略.Content-Length
參考
- https://developer.mozilla.org
- 《HTTP權威指南》
版權聲明
本文釋出于
, 允許非商業用途轉載, 但轉載必須保留原作者
樸瑞卿及連結:
https://blog.piaoruiqing.com. 如有授權方面的協商或合作, 請聯系郵箱: [email protected].
關于Fundebug
Fundebug專注于JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了20億+錯誤事件,付費客戶有陽光保險、核桃程式設計、荔枝FM、掌門1對1、微脈、青團社等衆多品牌企業。歡迎大家
免費試用!