Open bingoohuang opened 4 years ago
要计算 Content-Length 响应头就必须缓冲所有响应体数据,因为是先发送 Content-Length 响应头,然后再发送任何的响应体数据。这是一个鸡和蛋的问题。所以对于大响应来说,开销很大。 既然使用了 chunked 编码,就不应再设置 Content-Length 响应头了。 HTTP 1.0 协议是不支持 chunked 编码的,所以在没有 Content-Length 响应头时以连接断开作为响应体的末尾。 尽量使用 HTTP 1.1;毕竟现在连 nginx 的 proxy 模块也支持 HTTP 1.1 了。
在nginx中,如果采用gzip,如果是keep alive,则必然是chunked模式。
Response与Transfer-Encoding:chunked、Content-Length、Content-Encoding:gzip
gzip on;
gzip_disable "MSIE [1-6]\.";
gzip_min_length 1k;
#gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript application/json 'text/plain; charset=UTF-8' 'text/css; charset=UTF-8' 'application/x-javascript; charset=UTF-8' 'text/xml; charset=UTF-8' 'application/xml; charset=UTF-8' 'application/xml+rss; charset=UTF-8' 'text/javascript; charset=UTF-8' 'application/json; charset=UTF-8' 'application/json;charset=UTF-8';
chunked_transfer_encoding off;
见证代码逻辑:gzip 开启了 + chunked 关闭了 => keep alive 失效了:
在upstream显示配置keepalive_requests 也有利于性能提升
http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
为什么打开gzip、关闭chunked会关闭连接?
因为 Nginx 会采用即时压缩(On-The-Fly Compression),整个压缩过程在内存中流式完成。也就是说,Nginx 不会等文件 GZip 完成再返回响应,而是边压缩边响应,这样可以显著提高 TTFB(Time To First Byte,首字节时间,WEB 性能优化重要指标)。这样唯一的问题是,Nginx 开始返回响应时,它无法知道将要传输的文件最终有多大,也就是无法给出 Content-Length 这个响应头部。
对于 TCP 持久连接上的 HTTP 报文,客户端需要一种机制来准确判断结束位置,所以HTTP Server不启用持久连接(关闭连接的方式)。
所以合理的方式是打开gzip、chunked。
毁三观的图:
三观回正的图:
用了这么久HTTP, 你是否了解Content-Length和Transfer-Encoding ?
由Content-Length导致的问题引发的一系列思考:
前言
Content-Length, HTTP消息长度, 用十进制数字表示的八位字节的数目. 一般情况下, 很多工作都被框架完成, 我们很少去关注这部分内容, 但少数情况下发生了Content-Length与实际消息长度不一致, 程序可能会发生比较奇怪的异常, 如:
什么是Content-Length
Content-Length是HTTP消息长度, 用十进制数字表示的八位字节的数目, 是Headers中常见的一个字段. Content-Length应该是精确的, 否则就会导致异常 (特别地, HTTP1.0中这个字段可有可无).
Content-Length首部指示出报文中实体主体的字节大小. 这个大小是包含了所有内容编码的, 比如, 对文本文件进行了gzip压缩的话, Content-Length首部指的就是压缩后的大小而不是原始大小.
Content-Length是如何工作的
Content-Length使用十进制的数字表示了消息的长度, 服务端/客户端通过它来得知后续要读取消息的长度.
如果这个长度不正确, 会发生如下情况:
不确定Content-Length的值怎么办
Content-Length首部指示出报文中实体主体的字节大小. 但如在请求处理完成前无法获取消息长度, 我们就无法明确指定Content-Length, 此时应该使用Transfer-Encoding: chunked
什么是Transfer-Encoding: chunked
数据以一系列分块的形式进行发送. Content-Length 首部在这种情况下不被发送. 在每一个分块的开头需要添加当前分块的长度, 以十六进制的形式表示,后面紧跟着 \r\n , 之后是分块本身, 后面也是\r\n. 终止块是一个常规的分块, 不同之处在于其长度为0.
结语