[转]http返回头中content-length与Transfer-Encoding: chunked的问题释疑

本文详细阐述了在服务器与手机客户端交互过程中,当动态生成的XML文件大小达到一定阈值时,HTTP响应头从包含content-length变为使用Transfer-Encoding:chunked的原因及解决方法。

 

原地址:http://www.blogjava.net/anchor110/articles/336371.html

http返回头中content-length与Transfer-Encoding: chunked的问题释疑

先说说问题出现的背景:

公司服务器与手机客户端交互,客户端请求一个动态生成的XML文件,在用firebug查看http响应头的时候,有时候发现有content- length属性,有时候没有这个属性,取而代之的是Transfer-Encoding: chunked属性。由于客户端强制要求,服务器端必须返回content-length,否则,客户端将不予解析。于是测试发现,当XML文件很小的时 候,是有content-length属性的,到达一个值时,就成了Tansfer-Encoding:chunked。

再引用一段话,解释一下Transfer-Encoding:chunked这个属性的意义:

通常,HTTP协议中使用Content-Length这个头来告知数据的长度。然后,在数据下行的过程中,Content-Length的方式要预先在服务器中缓存所有数据,然后所有数据再一股脑儿地发给客户端。

如果要一边产生数据,一边发给客户端,WEB 服务器就需要使用"Transfer-Encoding: chunked"这样的方式来代替Content-Length。

最后说说自己的理解与解决方式:

通过种种迹象,我得出的结论是,JSP页面有一个缓存大小,当输出数据的长度没有到达这个大小的时候,服务器是知道总的数据长度的,所以服务器会输出 content-length头。但如果超过缓存大小,那么,缓存一满,服务器就得输出内容给客户端,所以,不能判断整个内容的大小,于是返回 Transfer-Encoding:chunked这个头信息。

解决方式是:在JSP页面中加入代码,response.setBufferSize(402800);40820即400K,其实只要这个值大于你返回的数据的大小就行了。具体设置多少,你可以根据实际情况,合理配置。另外说一句,在page指令中加入buffer="400kb",是不管用的,我测试 的情况是这样。

注解:

当使用Transfer-Encoding: chunked时,传送的实际长度将放到实际内容的首行,如以下这个列子,b就是实际的长度

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Set-Cookie: JSESSIONID=8A7461DDA53B4C4DD0E89D73219CB5F8; Path=/

Content-Type: text/html;charset=UTF-8

Transfer-Encoding: chunked

Date: Wed, 10 Nov 2010 07:10:05 GMT

b

helloworld!

3

123

0

转载于:https://www.cnblogs.com/foxhengxing/archive/2011/12/02/2272387.html

<think>好的,我现在需要解决用户的问题:为什么配置了Nginx的chunked_transfer_encoding on,但响应头里没有Transfer-Encoding: chunked。首先,我得回忆一下Nginx的相关配置和HTTP协议的要求。 用户已经设置了chunked_transfer_encoding on,但响应头没有出现预期的字段。可能的原因有很多,我需要逐步分析。 首先,检查Nginx的配置是否正确。可能用户配置的位置块是否正确应用了?比如是否在正确的location或server块中设置了该指令。还要看是否有其他配置覆盖了这个设置,比如全局的proxy_buffering是否关闭了,因为如果proxy_buffering是开启的,Nginx会缓冲整个响应,这样就不会使用分块传输了。所以用户需要确认proxy_buffering是否确实关闭了。 接下来考虑HTTP协议版本的问题。分块传输编码在HTTP/1.1中支持,但HTTP/1.0不支持。如果客户端使用的是HTTP/1.0,即使服务器配置了,也不会生效。用户可以通过curl -v查看响应使用的协议版本,确认是否是HTTP/1.1。 然后,后端服务器的响应是否有Content-Length头?如果后端已经提供了Content-Length,Nginx可能会优先使用这个,而不启用分块传输。这时候需要检查后端应用是否设置了该头,或者Nginx是否有模块自动添加了Content-Length。 另外,检查后端是否本身返回了分块传输。如果后端已经分块,Nginx可能直接透传,而不添加Transfer-Encoding头。这时候需要确认后端的行为。 还有可能的是响应体的大小。如果响应体很小,Nginx可能会直接发送完整的Content-Length,而不使用分块。用户可以用大文件测试,看是否出现分块。 此外,某些Nginx模块或配置可能影响分块传输,比如gzip是否开启。如果启用了gzip,可能在压缩过程中缓冲数据,导致分块无法生效。需要确认gzip的设置,或者尝试暂时关闭gzip测试。 用户可能需要通过curl -v来查看详细的响应头,或者使用Wireshark抓包分析实际的传输情况,确认是否有分块的特征,比如每个数据块的大小前缀。 总结下来,可能的原因有:配置被覆盖、HTTP版本问题、后端提供Content-Length、响应体太小、模块冲突等。需要逐一排查这些可能性,帮助用户找到问题根源。</think>当Nginx配置了`chunked_transfer_encoding on`但响应头未出现`Transfer-Encoding: chunked`时,可能涉及以下多维度的技术原因: --- ### 一、配置冲突检测矩阵 ```mermaid graph TD A[缺失chunked头] --> B[协议版本] A --> C[缓冲机制] A --> D[响应特征] A --> E[后端行为] B --> B1(HTTP/1.0) C --> C1(proxy_buffering未关闭) C --> C2(gzip冲突) D --> D1(Content-Length已存在) D --> D2(空响应体) E --> E1(后端强制Content-Length) ``` --- ### 二、核心排查步骤 #### 1. 协议版本验证 ```bash # 查看实际使用的HTTP协议版本 curl -v 2>&1 | grep -i 'HTTP/' ``` **关键现象**: 若输出`HTTP/1.0 200 OK`,则分块传输自动禁用 **解决方案**: 在配置中强制协议版本: ```nginx proxy_http_version 1.1; ``` --- #### 2. 缓冲配置检查 **冲突检测**: ```nginx # 确认没有冲突配置 location /webapi/user/extractMinutes { proxy_buffering off; # 必须关闭 chunked_transfer_encoding on; # 检查可能覆盖的配置 proxy_max_temp_file_size 0; # 禁用临时文件 proxy_request_buffering off; # 关闭请求缓冲 } ``` **缓冲状态验证**: ```bash # 查看实际生效配置 nginx -T | grep -A 10 'location /webapi/user/extractMinutes' ``` --- #### 3. 内容长度冲突 **响应头分析**: ```bash curl -I 2>&1 | grep -iE 'Content-Length|Transfer-Encoding' ``` **故障场景**: 当后端响应包含`Content-Length`头时,Nginx优先使用固定长度传输 **强制解决方案**: ```nginx proxy_force_ranges on; # 强制覆盖内容长度 ``` --- ### 三、后端行为诊断 #### 1. 后端响应特征检测 ```bash # 直接请求后端服务验证 curl -v http://127.0.0.1:40330/extractMinutes ``` **关键观察点**: - 后端是否自带`Transfer-Encoding`头 - 后端是否发送`Content-Length`头 --- #### 2. 分块传输强制测试 **生成流式响应**: ```bash # 使用socat模拟分块响应 socat -v tcp-listen:40330,reuseaddr,fork exec:'printf "HTTP/1.1 200 OK\r\n\r\n5\r\nhello\r\n0\r\n\r\n"' ``` **预期结果**: 通过Nginx代理后应看到: ``` Transfer-Encoding: chunked ``` --- ### 四、高级调试技巧 #### 1. 内核级报文分析 ```bash # 使用tcpdump捕获实际报文 sudo tcpdump -i lo -s 0 -A 'tcp port 40330 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)' ``` **分块传输特征**: 观察数据包中的`0d 0a`结束符和十六进制块长度前缀 --- #### 2. Nginx调试日志 ```nginx # 启用debug级别日志 error_log /var/log/nginx/debug.log debug; ``` **日志分析重点**: 查找`http filter chunked`相关日志条目 --- ### 五、常见陷阱案例 #### 案例1:gzip压缩冲突 ```nginx # gzip模块会缓冲数据 gzip on; gzip_min_length 0; # 允许压缩小文件 ``` **解决方案**: 禁用压缩或调整阈值: ```nginx gzip off; # 或 gzip_min_length 1024k; # 确保不压缩目标响应 ``` --- #### 案例2:缓存模块干扰 ```nginx proxy_cache_path /tmp/cache keys_zone=mycache:10m; location /webapi/user/extractMinutes { proxy_cache mycache; # 即使proxy_cache off也会影响 } ``` **异常表现**: 缓存逻辑会强制获取完整响应 --- ### 六、配置验证工作流 ```mermaid sequenceDiagram 用户->>Nginx: 发送请求 Nginx->>后端: 代理请求 后端->>Nginx: 流式响应 alt 分块条件满足 Nginx->>客户端: Transfer-Encoding: chunked else Nginx->>客户端: Content-Length end ``` 通过上述多维度排查,可精准定位缺失`Transfer-Encoding: chunked`的根本原因。建议优先检查协议版本、缓冲配置和后端响应特征这三个关键维度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值