1. 程式人生 > >HTTP協議之chunk編碼(分塊傳輸編碼)

HTTP協議之chunk編碼(分塊傳輸編碼)

分塊傳輸編碼Chunked transfer encoding)是超文字傳輸協議(HTTP)中的一種資料傳輸機制,允許HTTP由應用伺服器傳送給客戶端應用( 通常是網頁瀏覽器)的資料可以分成多個部分。分塊傳輸編碼只在HTTP協議1.1版本(HTTP/1.1)中提供。

通常,HTTP應答訊息中傳送的資料是整個傳送的,Content-Length訊息頭欄位表示資料的長度。資料的長度很重要,因為客戶端需要知道哪裡是應答訊息的結束,以及後續應答訊息的開始。然而,使用分塊傳輸編碼,資料分解成一系列資料塊,並以一個或多個塊傳送,這樣伺服器可以傳送資料而不需要預先知道傳送內容的總大小。通常資料塊的大小是一致的,但也不總是這種情況。

HTTP 1.1引入分塊傳輸編碼提供了以下幾點好處:

  1. HTTP分塊傳輸編碼允許伺服器為動態生成的內容維持HTTP持久連線。通常,持久連結需要伺服器在開始傳送訊息體前傳送Content-Length訊息頭欄位,但是對於動態生成的內容來說,在內容建立完之前是不可知的。[動態內容,content-length無法預知]
  2. 分塊傳輸編碼允許伺服器在最後傳送訊息頭欄位。對於那些頭欄位值在內容被生成之前無法知道的情形非常重要,例如訊息的內容要使用雜湊進行簽名,雜湊的結果通過HTTP訊息頭欄位進行傳輸。沒有分塊傳輸編碼時,伺服器必須緩衝內容直到完成後計算頭欄位的值並在傳送內容前傳送這些頭欄位的值。[雜湊簽名,需緩衝完成才能計算]
  3. HTTP伺服器有時使用壓縮 (gzip或deflate)以縮短傳輸花費的時間。分塊傳輸編碼可以用來分隔壓縮物件的多個部分。在這種情況下,塊不是分別壓縮的,而是整個負載進行壓縮,壓縮的輸出使用本文描述的方案進行分塊傳輸。在壓縮的情形中,分塊編碼有利於一邊進行壓縮一邊傳送資料,而不是先完成壓縮過程以得知壓縮後資料的大小。[gzip壓縮,壓縮與傳輸同時進行]

   一般情況HTTP的Header包含Content-Length域來指明報文體的長度。有時候服務生成HTTP迴應是無法確定訊息大小的,比如大檔案的下載,或者後臺需要複雜的邏輯才能全部處理頁面的請求,這時用需要實時生成訊息長度,伺服器一般使用chunked編碼。

   在進行Chunked編碼傳輸時,在回覆訊息的Headers有transfer-coding域值為chunked,表示將用chunked編碼傳輸內容。使用chunked編碼的Headers如下(可以利用FireFox的FireBug外掛或HttpWatch檢視Headers資訊):

   採用以下方式編碼:   
    Chunked-Body=*chunk   
           "0"CRLF   
           footer   
           CRLF   
    chunk=chunk-size[chunk-ext]CRLF   
        chunk-dataCRLF   

    hex-no-zero=<HEXexcluding"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 

    編碼使用若干個Chunk組成,由一個標明長度為0的chunk結束,每個Chunk有兩部分組成,第一部分是該Chunk的長度和長度單位(一般不 寫),第二部分就是指定長度的內容,每個部分用CRLF隔開。在最後一個長度為0的Chunk中的內容是稱為footer的內容,是一些沒有寫的頭部內 容。       下面給出一個Chunked的解碼過程(RFC文件中有)   
    length:=0   
readchunk-size,chunk-ext(ifany)andCRLF   
    while(chunk-size>0){   
    readchunk-dataandCRLF   
    appendchunk-datatoentity-body   
    length:=length+chunk-size   
    readchunk-sizeandCRLF   
    }   
 readentity-header   
    while(entity-headernotempty){   
    appendentity-headertoexistingheaderfields   
    readentity-header   
    }   
Content-Length:=length   
 Remove"chunked"fromTransfer-Encoding