http響應chunked格式分析


有的時候服務器生成HTTP回應是無法確定信息大小的,這時用Content-Length就無法事先寫入長度,而需要實時生成消息長度,這時服務器一般采用Chunked編碼。

在進行Chunked編碼傳輸時,在回復消息的頭部有transfer-coding並定義為Chunked,表示將用Chunked編碼傳輸內容。

 

Chunked編碼使用若干個Chunk串連而成,由一個標明長度為0的chunk標示結束。每個Chunk分為頭部和正文兩部分,頭部內容指定下一段正文的字符總數(十六進制的數字)和數量單位(一般不寫),正文部分就是指定長度的實際內容,兩部分之間用回車換行(CRLF)隔開。在最后一個長度為0的Chunk中的內容是稱為footer的內容,是一些附加的Header信息(通常可以直接忽略)。

 

我們來模擬一下數據結構:
[Chunk大小][回車][Chunk數據體][回車][Chunk大小][回車][Chunk數據體][回車][0][回車][footer內容(有的話)][回車]

注意chunk-size是以十六進制的ASCII碼表示的,比如86AE(實際的十六進制應該是:38366165),計算成長度應該是:34478,表示從回車之后有連續的34478字節的數據。
跟蹤了www.yahoo.com的返回數據,發現在chunk-size中,還會多一些空格。可能是固定長度為7個字節,不滿7個字節的,就以空格補足,空格的ASCII碼是0x20。

 

    解碼流程:
    對chunked編碼進行解碼的目的是將分塊的chunk-data整合恢復成一塊作為報文體,同時記錄此塊體的長度。
    RFC2616中附帶的解碼流程如下:(偽代碼)
    length := 0         //長度計數器置0
    read chunk-size, chunk-extension (if any) and CRLF      //讀取chunk-size, chunk-extension
                                                          //和CRLF
    while(chunk-size > 0 )   {            //表明不是last-chunk
          read chunk-data and CRLF            //讀chunk-size大小的chunk-data,skip CRLF
          append chunk-data to entity-body     //將此塊chunk-data追加到entity-body后
          read chunk-size and CRLF          //讀取新chunk的chunk-size 和 CRLF
    }
    read entity-header      //entity-header的格式為name:valueCRLF,如果為空即只有CRLF
    while (entity-header not empty)   //即,不是只有CRLF的空行
    {
       append entity-header to existing header fields
       read entity-header
    }
    Content-Length:=length      //將整個解碼流程結束后計算得到的新報文體length
                                 //作為Content-Length域的值寫入報文中
    Remove "chunked" from Transfer-Encoding  //同時從Transfer-Encoding中域值去除chunked這個標記

 

Sample

Encoded response

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

25
This is the data in the first chunk

1A
and this is the second one
0

same as above, raw bytes in hex

0000-000F   48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d   HTTP/1.1 200 OK.
0010-001F   0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74   .Content-Type: t
0020-002F   65 78 74 2f 70 6c 61 69 6e 0d 0a 54 72 61 6e 73   ext/plain..Trans
0030-003F   66 65 72 2d 45 6e 63 6f 64 69 6e 67 3a 20 63 68   fer-Encoding: ch
0040-004F   75 6e 6b 65 64 0d 0a 0d 0a 32 35 0d 0a 54 68 69   unked....25..Thi
0050-005F   73 20 69 73 20 74 68 65 20 64 61 74 61 20 69 6e   s is the data in
0060-006F   20 74 68 65 20 66 69 72 73 74 20 63 68 75 6e 6b    the first chunk
0070-007F   0d 0a 0d 0a 31 41 0d 0a 61 6e 64 20 74 68 69 73   ....1A..and this
0080-008F   20 69 73 20 74 68 65 20 73 65 63 6f 6e 64 20 6f    is the second o
0090-009F   6e 65 0d 0a 30 0d 0a 0d 0a                        ne..0....

same as above, in Java code

public static final byte[] CHUNKED_RESPONSE; static { StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.1 200 OK/r/n"); sb.append("Content-Type: text/plain/r/n"); sb.append("Transfer-Encoding: chunked/r/n/r/n"); sb.append("25/r/n"); sb.append("This is the data in the first chunk/r/n"); // 37 bytes of payload // (conveniently consisting of ASCII characters only) sb.append("/r/n1A/r/n"); sb.append("and this is the second one"); // 26 bytes of payload // (conveniently consisting of ASCII characters only) sb.append("/r/n0/r/n/r/n"); CHUNKED_RESPONSE = sb.toString().getBytes(java.nio.charset.Charset.forName("US-ASCII")); } 

Decoded data

This is the data in the first chunk
and this is the second one

基本上checked的編碼方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM