网上使用chunked编码的网站似乎并不是很多,除了那些使用gzip压缩的网站,例:google.com,还有就是大部分打开gzip压缩的php论坛。
7 g1 R: Y- |8 p( W; e% p根据本人的理解,使用chunked编码的主要好处就在于一些程序的运算出过程中,可以动态的输出内容。( v6 @: Q/ ~( o
例如,要在后台处理一个小时的运算,但又不希望用户等一个小时才能看到结果。这时就可采用chunked编码将内容分块输出,用户随时都可以接收到最新的处理结果。0 K7 R' {/ y, J; C2 y
asp关闭了缓存的输出模式,就是chunked编码的。(response.buffer = false): w% f8 @; S7 u3 v
而每一次的response.write,都是一个chunked,所以不要使用的太频繁哦,否则chunk数量太多,额外的数据太浪费空间了。
) n; w' o! ?* p/ @$ V( K若想了解chunked的具体编码结构,用asp关闭缓存调试蛮方便的。:)* W# y, R9 \2 l' w; R$ q
我们先来看看rfc2616中对chunked的定义:1 G- b$ [6 R( O: ^5 n Z' V6 H, V
chunked-body = *chunk% A+ _+ }2 j" m3 a
last-chunk9 a/ S- P( E% O" B% y
trailer: \' ^* h! V0 \$ @& `- _
crlf8 J' V K% a: f; p8 ^
chunk = chunk-size [ chunk-extension ] crlf$ n, w% i1 ^8 J& ]( f+ d6 j
chunk-data crlf
+ c* L! d2 c( ]/ {1 t5 Uchunk-size = 1*hex) b. `2 \7 m, _. H7 C
last-chunk = 1*(0) [ chunk-extension ] crlf9 s* i0 g0 U8 r$ ^+ \
chunk-extension= *( ; chunk-ext-name [ = chunk-ext-val ] )
3 u0 \ X; I6 \8 r* ~& q% [9 a# hchunk-ext-name = token
3 A O! k/ P/ Qchunk-ext-val = token | quoted-string
0 `& k2 e; G" f; W3 {) @chunk-data = chunk-size(octet)
* j0 w6 o6 z% y/ v. O+ U2 R5 B- Ytrailer = *(entity-header crlf)1 b3 L% G( {& t6 |; W
我们来模拟一下数据结构:% j2 b# K+ _/ p) M! ^7 X" Q, v3 y0 h3 H
[chunk大小][回车][chunk数据体][回车][chunk大小][回车][chunk数据体][回车][0][回车]$ `1 Y" U. F i4 U
注意chunk-size是以十六进制的ascii码表示的,比如86ae(实际的十六进制应该是:38366165),计算成长度应该是:34478,表示从回车之后有连续的34478字节的数据。6 l2 z8 t O& ]! q" s
跟踪了的返回数据,发现在chunk-size中,还会多一些空格。可能是固定长度为7个字节,不满7个字节的,就以空格补足,空格的ascii码是0x20。
4 V, e: ~4 n V6 W+ M以下是解码过程的伪代码:
/ n) B- w# {% A3 Qlength := 0//用来记录解码后的数据体长度/ l9 L- a+ |" ?" A! d
read chunk-size, chunk-extension (if any) and crlf//第一次读取块大小5 c! \' q5 D. u! g- a8 k& e1 f; r- A
while (chunk-size > 0) {//一直循环,直到读取的块大小为0* |1 g" g: g. x$ @
read chunk-data and crlf//读取块数据体,以回车结束
) ~) s( {7 i5 bappend chunk-data to entity-body//添加块数据体到解码后实体数据
7 k! I, X# J7 b9 x1 Plength := length + chunk-size//更新解码后的实体长度
2 Q) P# |3 ]" Z& e" Cread chunk-size and crlf//读取新的块大小
7 M; q3 }7 \& r% Y4 i9 u}
* z8 W- I; w' `" \$ \read entity-header//以下代码读取全部的头标记
( w, g% O4 l; K" H0 o5 y% j0 @while (entity-header not empty) {' {9 Y U5 b X2 U' M0 \; h! w- y
append entity-header to existing header fields
6 }( B9 U; }& Hread entity-header
& c1 a6 r. }1 I}
6 L. W/ o; z, `' R) @/ H3 gcontent-length := length//头标记中添加内容长度
. o2 F' m- Q- X2 iremove chunked from transfer-encoding//头标记中移除transfer-encoding
" @! _8 S) j% j& ^* ?有空再研究一下gzip+chunked是如何编码的,估计是每个chunk块进行一次gzip独立压缩。7 s" H! S& o) y
使用了chunked,自然会在性能上稍微打点折扣,因为比正常的数据体多出了一些额外的消耗。
, P7 E9 M6 t, a% E但是有一些情况下,必需要使用分块输出,这也是不得已而为之.
( F: `( M' M3 A' V, g b( C# c. _" x
更多网页制作信息请查看: 网页制作 |
|