Chunked编码
前不久同事調接口時發現了一個奇怪的問題,直接使用CURL請求接口,返回沒有問題;而通過Socket請求時返回的信息多了兩行。查看HTTP響應頭發現,有時候會指定Content-Length,有時則是Transfer-Encoding: chunked。當chunked編碼時,通過socket請求就出錯。而如果此時服務端指定返回的長度則沒問題。
問題就出在此!通常情況下會通過Content-Length來指定返回內容的長度,而有些時候無法確定長度時,可采用chunked編碼動態返回。
CHUNKED描述
一般HTTP通信時,會使用Content-Length頭信息性來通知用戶代理(通常意義上是瀏覽器)服務器發送的文檔內容長度,該頭信息定義于HTTP1.0協議RFC 1945 10.4章節中。瀏覽器接收到此頭信息后,接受完Content-Length中定義的長度字節后開始解析頁面,但如果服務端有部分數據延遲發送嗎,則會出現瀏覽器白屏,造成比較糟糕的用戶體驗。
解決方案是在HTTP1.1協議中,RFC 2616中14.41章節中定義的Transfer-Encoding: chunked的頭信息,chunked編碼定義在3.6.1中,所有HTTP1.1 應用都支持此使用trunked編碼動態的提供body內容的長度的方式。進行Chunked編碼傳輸的HTTP數據要在消息頭部設置:Transfer-Encoding: chunked表示Content Body將用chunked編碼傳輸內容。根據定義,瀏覽器不需要等到內容字節全部下載完成,只要接收到一個chunked塊就可解析頁面.并且可以下載html中定義的頁面內容,包括js,css,image等。
格式
http://zh.wikipedia.org/wiki/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81
如果一個HTTP消息(請求消息或應答消息)的Transfer-Encoding消息頭的值為chunked,那么,消息體由數量未定的塊組成,并以最后一個大小為0的塊為結束。
每一個非空的塊都以該塊包含數據的字節數(字節數以十六進制表示)開始,跟隨一個CRLF (回車及換行),然后是數據本身,最后塊CRLF結束。在一些實現中,塊大小和CRLF之間填充有白空格(0x20)。最后一塊是單行,由塊大小(0),一些可選的填充白空格,以及CRLF。最后一塊不再包含任何數據,但是可以發送可選的尾部,包括消息頭字段。消息最后以CRLF結尾。
模擬socket請求
模擬請求后請求數據和返回數據如下圖:
Transfer-Encoding指定chunked編碼,并且分成兩段,分別對應長度和內容,以0結束。可以對照上面的格式查看。
編碼解析
通常這種問題發生在使用自己封裝的socket方法時,并且HTTP版本使用1.1時會有該問題,所以可以使用1.0避免chunked編碼解析的問題,或者使用CURL或者其他封裝好的方法。 如果想解析chunked編碼,也可參考手冊上的方法: http://cn2.php.net/manual/en/function.fsockopen.php
function unchunkHttpResponse($str=null) { if (!is_string($str) or strlen($str) < 1) { return false; } $eol = "\r\n"; $add = strlen($eol); $tmp = $str; $str = ''; do { $tmp = ltrim($tmp); $pos = strpos($tmp, $eol); if ($pos === false) { return false; } $len = hexdec(substr($tmp,0,$pos)); if (!is_numeric($len) or $len < 0) { return false; } $str .= substr($tmp, ($pos + $add), $len); $tmp = substr($tmp, ($len + $pos + $add)); $check = trim($tmp); } while(!empty($check)); unset($tmp); return $str; }
總結
- 上一篇: HTTPS 原理详解
- 下一篇: 简易HTTP协议解析