Response与Transfer-Encoding:chunked、Content-Length、Content-Encoding:gzip

缘起

了解HTTP 1.1和HTTP1.0的区别的同学都知道,Transfer-Encoding:chunked , Connection:keep-alive 都是HTTP 1.1的新特性;

Connection:keep-alive 使得一次连接可以干多次HTTP请求的活儿,而HTTP1.0协议每次tcp连接只能处理一个HTTP请求;

另外,对于HTTP 1.0来讲,如果一次HTTP的响应内容很多,而且又无法提前预知内容的多少,那么就不使用content-length ,输出完成后,直接关闭连接即可,一定程度上来讲,content-length对于HTTP 1.0来讲,是可有可无的;

而对于HTTP1.1 来讲,如果 connection: keep-alive ,而且又不能提前预知内容多少的话,该怎么办呢? 这就是为什么要有Transfer-Encoding:chunked 的原因了。

有了这些知识之后,我们再来看一种现象,为什么同样是HTTP1.1 ,有的请求就使用的是 content-length ,而又的请求就使用的Transfer-Encoding:chunked 呢? 需要什么特殊的设置吗?

可能请求输出的内容并不多,比如就10行,但是每行内容需要5s钟的时间来生成,如果能分块儿输出,是不是用户体验会好一些?那么又如何分块儿输出呢?

从协议上来讲,如果输出中有 content-length 则显然不是分块儿输出的,如果是Transfer-Encoding:chunked 则可能是分块儿输出的。

 

查资料:

一般服务器采用 Transfer-Encoding:chunked 有两种情况:

1. 应用程序已经输出给webserver很多内容(就是webserver的buffer满了),但是还是没有要结束的意思(就是还没输出完),则webserver放弃输出content-length,如果是HTTP1.0 ,则直接输出内容(输出完关闭连接就ok了);如果是HTTP1.1,则采用Transfer-Encoding:chunked 的方式输出。

2. 应用程序主动flush内容到客户端,如果是PHP,为: ob_flush(); flush(); (参看: http://php.net/flush )

 

所以: 对于页面服务,如果要输出的内容很多,可以生成一部分就flush一部分,让浏览器尽快渲染给用户,给用户一个更好的使用体验。

Content-Encoding:gzip

gzip是内容编码,是否压缩; 压缩式在传输之前进行的,所以传输的分块儿是按照压缩后的数据分块儿的(似乎有点儿废话了)

Nginx中如果启用了gzip压缩,则必然采用Transfer-Encoding:chunked 的方式输出,原因如下:

Nginx中Gzip模块和r->headers_out.content_length_n

r->headers_out.content_length_n :这个在Nginx内部用于表述请求返回内容的长度。但注意这不是完全相等的,只有在 r->headers_out.content_length_n >=0的时候,才有意义。比如说,通常后端的upstream(比如说PHP),如果没有在脚本中强制header输出content-length,则默认在nginx中 r->headers_out.content_length_n = -1。

Gzip模块也是一个典型的Filter模块。这里简单介绍下,后续可以详细描述。在header filter中会直接清空 r->headers_out.content_length_n和header中输出的content_length。为什么要清空呢?主要是因为gzip要对内容模块进行压缩处理,而在header filter的时候,gzip模块不可能计算出压缩后的内容长度(原因是在nginx中,header 输出和body的输出是完全两个不同的阶段),所以最好的办法就是在清空header中的content-length。这样结合之前的介绍的chunked模块,可以看出:在nginx中,如果采用gzip,如果是keep alive,则必然是chunked模式。

 

参考资料:

http://blog.xiuwz.com/tag/content-length/

http://lokki.iteye.com/blog/1072327

http://www.cnblogs.com/foxhengxing/archive/2011/12/02/2272387.html

 

 

留下评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据