网上使用chunked编码的网站似乎并不是很多,除了那些使用gzip压缩的网站,例:google.com,还有就是大部分打开gzip压缩的php论坛。' q9 ^# h* I* [4 W( u! x
根据本人的理解,使用chunked编码的主要好处就在于一些程序的运算出过程中,可以动态的输出内容。
1 H8 C7 n* r$ N9 T% o例如,要在后台处理一个小时的运算,但又不希望用户等一个小时才能看到结果。这时就可采用chunked编码将内容分块输出,用户随时都可以接收到最新的处理结果。1 | Z, @- P/ @8 q a, Y0 l$ M
asp关闭了缓存的输出模式,就是chunked编码的。(response.buffer = false)
; U! j, d+ b- E* d* N# N; F; P' ^+ f而每一次的response.write,都是一个chunked,所以不要使用的太频繁哦,否则chunk数量太多,额外的数据太浪费空间了。
# @8 a) d5 I* |4 s4 W- Z9 }若想了解chunked的具体编码结构,用asp关闭缓存调试蛮方便的。:)
1 @, M+ R4 z* E1 T, s我们先来看看rfc2616中对chunked的定义: t' E: @- }- u5 d, z' n3 ?
chunked-body = *chunk! Z5 g7 ~/ [/ O6 ?/ h9 [
last-chunk
6 F2 T* c1 s1 wtrailer
- E+ x2 S1 ?$ e2 Y4 d s7 [crlf
$ I2 M! u* g* W5 c8 T) Tchunk = chunk-size [ chunk-extension ] crlf! {- H7 W% R& `+ l9 n6 {5 L
chunk-data crlf/ N# i& Y- g3 |4 T h
chunk-size = 1*hex; B, e. d; w% A1 o2 s4 \8 y
last-chunk = 1*(0) [ chunk-extension ] crlf
4 ?7 V- u: ~# t8 `5 Mchunk-extension= *( ; chunk-ext-name [ = chunk-ext-val ] )9 u7 c( }) \1 d
chunk-ext-name = token) V+ n( {- K% e% U" n( b
chunk-ext-val = token | quoted-string
) V8 R# r5 [. h5 V9 J0 rchunk-data = chunk-size(octet)) q1 i7 `1 `0 g2 H. L1 @) y
trailer = *(entity-header crlf)
+ n! Q% R, D! K5 G5 M/ E我们来模拟一下数据结构:' n ^5 q: q7 {# `3 s7 {4 C
[chunk大小][回车][chunk数据体][回车][chunk大小][回车][chunk数据体][回车][0][回车]6 B& C# R8 B3 t7 K- U
注意chunk-size是以十六进制的ascii码表示的,比如86ae(实际的十六进制应该是:38366165),计算成长度应该是:34478,表示从回车之后有连续的34478字节的数据。$ v8 S# ?$ M' }. S* _9 Y- L( G
跟踪了的返回数据,发现在chunk-size中,还会多一些空格。可能是固定长度为7个字节,不满7个字节的,就以空格补足,空格的ascii码是0x20。
& l) j6 p6 Y7 {: Z1 [9 l( D/ Q以下是解码过程的伪代码:
- c, x, Q: u$ \5 W$ r2 v+ dlength := 0//用来记录解码后的数据体长度
+ z8 A, o- D9 }( m! Yread chunk-size, chunk-extension (if any) and crlf//第一次读取块大小
3 O: Q! M* Z3 Q1 `# G g" {9 a$ J$ ?) dwhile (chunk-size > 0) {//一直循环,直到读取的块大小为0# |5 o: V" D0 k) B# y$ q" T5 m
read chunk-data and crlf//读取块数据体,以回车结束
) r! ]) f ?' U9 a+ h% W$ Happend chunk-data to entity-body//添加块数据体到解码后实体数据
1 E+ [$ _! k6 a5 Flength := length + chunk-size//更新解码后的实体长度( |7 m4 z7 r2 q2 U3 s
read chunk-size and crlf//读取新的块大小
1 t$ j9 P5 @) W8 s+ Q}
/ \0 ^0 P3 V% dread entity-header//以下代码读取全部的头标记0 R/ c. c) \9 [( v( M- R
while (entity-header not empty) {
0 \" I) S8 a3 i9 {1 U! \2 L" L" S7 xappend entity-header to existing header fields
! U J$ ~! k2 y" N" vread entity-header! V' n( }. r& f, m
}$ q2 \/ \ |( Q' l
content-length := length//头标记中添加内容长度' L7 }: O5 V" T+ p- f" A
remove chunked from transfer-encoding//头标记中移除transfer-encoding8 z8 D! a$ N+ }) J6 d- @
有空再研究一下gzip+chunked是如何编码的,估计是每个chunk块进行一次gzip独立压缩。
( n, y6 C0 b2 y I( W' P' E使用了chunked,自然会在性能上稍微打点折扣,因为比正常的数据体多出了一些额外的消耗。
8 ?* n) q4 B& y0 u但是有一些情况下,必需要使用分块输出,这也是不得已而为之.9 O+ Z* A6 v1 o1 ^: i* E& U5 J7 Z7 f. p
8 y5 L" J5 |! C+ ]2 m0 ]$ t
更多网页制作信息请查看: 网页制作 |
|