Chunked编码
前不久同事調(diào)接口時(shí)發(fā)現(xiàn)了一個(gè)奇怪的問(wèn)題,直接使用CURL請(qǐng)求接口,返回沒(méi)有問(wèn)題;而通過(guò)Socket請(qǐng)求時(shí)返回的信息多了兩行。查看HTTP響應(yīng)頭發(fā)現(xiàn),有時(shí)候會(huì)指定Content-Length,有時(shí)則是Transfer-Encoding: chunked。當(dāng)chunked編碼時(shí),通過(guò)socket請(qǐng)求就出錯(cuò)。而如果此時(shí)服務(wù)端指定返回的長(zhǎng)度則沒(méi)問(wèn)題。
問(wèn)題就出在此!通常情況下會(huì)通過(guò)Content-Length來(lái)指定返回內(nèi)容的長(zhǎng)度,而有些時(shí)候無(wú)法確定長(zhǎng)度時(shí),可采用chunked編碼動(dòng)態(tài)返回。
CHUNKED描述
一般HTTP通信時(shí),會(huì)使用Content-Length頭信息性來(lái)通知用戶(hù)代理(通常意義上是瀏覽器)服務(wù)器發(fā)送的文檔內(nèi)容長(zhǎng)度,該頭信息定義于HTTP1.0協(xié)議RFC 1945 10.4章節(jié)中。瀏覽器接收到此頭信息后,接受完Content-Length中定義的長(zhǎng)度字節(jié)后開(kāi)始解析頁(yè)面,但如果服務(wù)端有部分?jǐn)?shù)據(jù)延遲發(fā)送嗎,則會(huì)出現(xiàn)瀏覽器白屏,造成比較糟糕的用戶(hù)體驗(yàn)。
解決方案是在HTTP1.1協(xié)議中,RFC 2616中14.41章節(jié)中定義的Transfer-Encoding: chunked的頭信息,chunked編碼定義在3.6.1中,所有HTTP1.1 應(yīng)用都支持此使用trunked編碼動(dòng)態(tài)的提供body內(nèi)容的長(zhǎng)度的方式。進(jìn)行Chunked編碼傳輸?shù)腍TTP數(shù)據(jù)要在消息頭部設(shè)置:Transfer-Encoding: chunked表示Content Body將用chunked編碼傳輸內(nèi)容。根據(jù)定義,瀏覽器不需要等到內(nèi)容字節(jié)全部下載完成,只要接收到一個(gè)chunked塊就可解析頁(yè)面.并且可以下載html中定義的頁(yè)面內(nèi)容,包括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
如果一個(gè)HTTP消息(請(qǐng)求消息或應(yīng)答消息)的Transfer-Encoding消息頭的值為chunked,那么,消息體由數(shù)量未定的塊組成,并以最后一個(gè)大小為0的塊為結(jié)束。
每一個(gè)非空的塊都以該塊包含數(shù)據(jù)的字節(jié)數(shù)(字節(jié)數(shù)以十六進(jìn)制表示)開(kāi)始,跟隨一個(gè)CRLF (回車(chē)及換行),然后是數(shù)據(jù)本身,最后塊CRLF結(jié)束。在一些實(shí)現(xiàn)中,塊大小和CRLF之間填充有白空格(0x20)。最后一塊是單行,由塊大小(0),一些可選的填充白空格,以及CRLF。最后一塊不再包含任何數(shù)據(jù),但是可以發(fā)送可選的尾部,包括消息頭字段。消息最后以CRLF結(jié)尾。
模擬socket請(qǐng)求
模擬請(qǐng)求后請(qǐng)求數(shù)據(jù)和返回?cái)?shù)據(jù)如下圖:
Transfer-Encoding指定chunked編碼,并且分成兩段,分別對(duì)應(yīng)長(zhǎng)度和內(nèi)容,以0結(jié)束。可以對(duì)照上面的格式查看。
編碼解析
通常這種問(wèn)題發(fā)生在使用自己封裝的socket方法時(shí),并且HTTP版本使用1.1時(shí)會(huì)有該問(wèn)題,所以可以使用1.0避免chunked編碼解析的問(wèn)題,或者使用CURL或者其他封裝好的方法。 如果想解析chunked編碼,也可參考手冊(cè)上的方法: 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; }
總結(jié)
- 上一篇: HTTPS 原理详解
- 下一篇: 我姓徐媳妇姓荆该起个什么网名^qUxJg