進行Chunked編碼傳輸的HTTP Response會在消息頭部設置:
Transfer-Encoding: chunked
表示Content Body將用Chunked編碼傳輸內容。
Chunked編碼使用若干個Chunk串連而成,由一個標明長度為0的chunk標示結束。每個Chunk分為頭部和正文兩部分,頭部內容指定下一段正文的字符總數(十六進制的數字)和數量單位(一般不寫),正文部分就是指定長度的實際內容,兩部分之間用回車換行(CRLF)隔開。在最后一個長度為0的Chunk中的內容是稱為footer的內容,是一些附加的Header信息(通常可以直接忽略)。具體的Chunk編碼格式如下:
Chunked-Body = *chunk
"0" CRLF
footer
CRLF
chunk = chunk-size [ chunk-ext ] CRLF
chunk-data CRLF
hex-no-zero = <HEX excluding "0">
chunk-size = hex-no-zero *HEX
chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-value ] )
chunk-ext-name = token
chunk-ext-val = token | quoted-string
chunk-data = chunk-size(OCTET)
footer = *entity-header
RFC文檔中的Chunked解碼過程如下:
length := 0
read chunk-size, chunk-ext (if any) and CRLF
while (chunk-size > 0) {
read chunk-data and CRLF
append chunk-data to entity-body
length := length + chunk-size
read chunk-size and CRLF
}
read entity-header
while (entity-header not empty) {
append entity-header to existing header fields
read entity-header
}
Content-Length := length
Remove "chunked" from Transfer-Encoding
最后提供一段PHP版本的chunked解碼代碼:
$chunk_size = (integer)hexdec(fgets( $socket_fd, 4096 ) );
while(!feof($socket_fd) && $chunk_size > ) {
$bodyContent .= fread( $socket_fd, $chunk_size );
fread( $socket_fd, 2 ); // skip \r\n
$chunk_size = (integer)hexdec(fgets( $socket_fd, 4096 ) );
}
要解決服務器不返回Transfer-Encoding:chunked,在客戶端請求的時候可以使用http 1.0的協議。
下面說下:transfer-encoding:chunked的含義
Transfer-Encoding: chunked 表示輸出的內容長度不能確定,普通的靜態頁面、圖片之類的基本上都用不到這個。
但動態頁面就有可能會用到,但我也注意到大部分asp,php,asp.net動態頁面輸出的時候大部分還是使用Content-Length,沒有使用Transfer-Encoding: chunked。
不過如果結合:Content-Encoding: gzip 使用的時候,Transfer-Encoding: chunked還是比較有用的。
記得以前實現:Content-Encoding: gzip 輸出時,先把整個壓縮后的數據寫到一個很大的字節數組里(如 ByteArrayOutputStream),然后得到數組大小 -> Content-Length。
如果結合Transfer-Encoding: chunked使用,就不必申請一個很大的字節數組了,可以一塊一塊的輸出,更科學,占用資源更少。
這在http協議中也是個常見的字段,用於http傳送過程的分塊技術,原因是http服務器響應的報文長度經常是不可預測的,使用Content-length的實體搜捕並不是總是管用。
分塊技術的意思是說,實體被分成許多的塊,也就是應用層的數據,TCP在傳送的過程中,不對它們做任何的解釋,而是把應用層產生數據全部理解成二進制流,然后按照MSS的長度切成一分一分的,一股腦塞到tcp協議棧里面去,而具體這些二進制的數據如何做解釋,需要應用層來完成,所以在這之前,一快整體應用層的數據需要等它分成的所有TCP segment到達對方,重新組裝后,應用程序才使用自己的解碼方法還原它們。
HTTP1.1采用了持久的連接,也就是一次TCP的連接不馬上釋放,允許許多的請求跟響應在一個TCP的連接上發送,所以客戶機與服務器需要某種方式來標示一個報文在哪里結束和在下一個報文在哪里開始。簡單的方法是使用呢content-length,但這只有當報文長度可以預先判斷的時候才起作用,而對於動態的內容或者在發送數據前不能判定長度的情況下,可以使用分塊的方法來傳送編碼。如圖:
進行Chunked編碼傳輸的HTTP Response會在消息頭部設置:
Transfer-Encoding: chunked
表示Content Body將用Chunked編碼傳輸內容。
Chunked編碼使用若干個Chunk串連而成,由一個標明長度為0的chunk標示結束。每個Chunk分為頭部和正文兩部分,頭部內容指定下一段正文的字符總數(十六進制的數字)和數量單位(一般不寫),正文部分就是指定長度的實際內容,兩部分之間用回車換行(CRLF)隔開。在最后一個長度為0的Chunk中的內容是稱為footer的內容,是一些附加的Header信息(通常可以直接忽略)。
這里面只有一個有意義的chunke以及一個footer。第一個chunk,頭部是3134這兩個字節,表示的是1和4這兩個ascii字符,被http協議解釋為十六進制數14,也就是十進制的20。后面緊跟0d0a,再接着是20個字節的chunk正文(圖中的011e~0131)。
后面再接着0d0a,然后就是footer了,30表示ascii字符0,http解釋為長度是0(也說明了這是最后一個chunk),后面緊跟0d0a,然后正文部分為空,再接0d 0a表示結束