HTTP 1.1中有兩個實體頭(Entity-Header)直接與編碼相關,分別為Content-Encoding和Transfer-Encoding。
先說Content-Encoding, 該頭表示實體已經采用了的編碼方式.Content-Encoding是請求URL對應實體(Entity)本身的一部分.比如請求URL為 http://host/image.png.gz時,可能會得到的Content-Encoding為gzip.Content-Encoding的值是不區分大小寫的,目前HTTP1.1標准中已包括的有gzip/compress/deflate/identity等.
與Content-Encoding頭對應,HTTP請求中包含了一個Accept-Encoding頭,該頭用來說明用戶代理(User- Agent,一般也就是瀏覽器)能接受哪些類型的編碼. 如果HTTP請求中不存在該頭,服務器可以認為用戶代理能接受任何編碼類型.
接下來重點描述Transfer-Encoding, 該頭表示為了達到安全傳輸或者數據壓縮等目的而對實體進行的編碼. Transfer-Encoding與Content-Encoding的不同之處在於:
1, Transfer-Encoding只是在傳輸過程中才有的,並非請求URL對應實體的本身特性.
2, Transfer-Encoding是一個"跳到跳"頭,而Content-Encoding是"端到端"頭.
該頭的用途舉例如,請求URL為http://host/abc.txt,服務器發送數據時認為該文件可用gzip方式壓縮以節省帶寬,接收端看到Transfer-Encoding為gzip首先進行解碼然后才能得到請求實體.
此外多個編碼可能同時對同一實體使用,所以Transfer-Encoding頭中編碼順序相當重要,它代表了解碼的順序過程.同樣,Transfer- Encoding的值也是不區分大小寫的,目前HTTP1.1標准中已包括的有gzip/compress/deflate/identity /chunked等。
報文舉例:
Server: Apache-Coyote/1.1 Cache-Control: no-store Pragma: no-cache Expires: Thu, 01 Jan 1970 00:00:00 GMT Content-Type: text/html;charset=GBK Transfer-Encoding: chunked Content-Encoding: gzip Vary: Accept-Encoding Date: Mon, 01 Jul 2013 02:37:55 GMT a ......... 200 .=ks.....U..v..f......(..l....lCl..5.#5.t..{$d../X[......c.c@<,.$..^..n..7...q...v%...G....F~.T..P?.=............?.-......J.tU-..z.I.m[......h[...3K..1..U.k\3.K...<..........Oo....o.^......v).#.....(c... b..(.......3.I....R'......*...%o...9...(c....5.....V...4......NW.. .m./...]..}..L..Z.X=*.>.$=....{G7y....[f.(..M.........e..........Nh`.UU.n.....|ZE....,=.>l.JZ...v..y$5....ho.c....NB... ..\m.p..[J...A .I....6..RsL.q......6>.h.]Y....J.1.F...e......&Z....w...p...P..^.z+..H..SmS..i...q.m.TS.....(..K....U.0>.k 200 ..d)M19..}-.{....I.~mui...N....+k...j#..qdq.....x.7MaI3..K..Z....`...j...)4...^...=......B..~(. ..]...S........>=]9`...C:....|F+K........^.hiUGD.X.T.SY..bA...v..........O..S....f.P...IY;.oI ........FD...3.Q....e..........dL...T..M.<`Z...Kf.."pR.....Y6..+.f..e..Lw&.m..t...Vt..1..].'..3.Z...'.RI5..j..;.:...J..:.~...>i.V\.v..wum....aM..V...&c+....< Sf.F|.........I...Q.Q.3.....U..F...O.....!.R.E.....X...k.....z.tf.Xz....$.>)R.2..6... f.........KP7P...92.c..e......&.[.&yS.P.S. ....4. dn....p.^.N.@..{T7.Mf ..jUT. 200
一、Transfer-Encoding含義介紹
進行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 > 0) { $bodyContent .= fread( $socket_fd, $chunk_size ); fread( $socket_fd, 2 ); // skip /r/n $chunk_size = (integer)hexdec(fgets( $socket_fd, 4096 ) ); }
二、Content-Encoding含義介紹
Content-Encoding是HTTP協議的響應報文頭,一般形式如:
Content-Encoding:gzip,deflate,compress
Content-Encoding的說明中指出deflate指的是在RFC1950說明的zlib格式。也就是說當Content-Encoding為deflate時,內容應該為zlib格式。
compress具說chrome支持,但還沒見到哪個web服務器支持
gzip,deflate,zlib的關系:
deflate(RFC1951):一種壓縮算法,使用LZ77和哈弗曼進行編碼;
zlib(RFC1950):一種格式,是對deflate進行了簡單的封裝;
gzip(RFC1952):一種格式,也是對deflate進行的封裝.
可以看出deflate是最核心的算法,而zlib和gzip格式的區別僅僅是頭部和尾部不一樣,而實際的內容都是deflate編碼的,即:
gzip = gzip頭(10字節) + deflate編碼的實際內容 + gzip尾(8字節)
[GZIP的實現可參考GzipOutputStream.Java]
zlib = zlib頭 + deflate編碼的實際內容 + zlib尾
訪問www.163.com. 響應報文含有gzip頭,而www.baidu.com的響應報文沒有gzip頭。
看到gzip大家都很好的支持,有無gzip頭都沒有問題。
(以下內容本人未做驗證)
對deflate即zlib格式:
那么在IE上面是打不開頁面的,包括IE6,IE7,IE8,提示為一片空白或者出錯。但是在其他的瀏覽器如Firefox,Chrome,Opera等上面都能正常打開。要讓IE能夠正常打開頁面,內容必須是deflate原始格式的數據,即去掉zlib頭和zlib尾。不知道IE為什么不修改這個 Bug,按理說在IE6就出現的這種很簡單的問題,IE8不應該出現才對。
為了照顧IE,只好在壓縮deflate的時候去掉zlib頭和zlib尾,還好其他的瀏覽器也都能正常處理這種原始的deflate格式。