解决 nginx 反向代理网页首尾出现神秘字符的问题

2011-07-15

一台内网 LAMP 服务器上运行 MediaWiki,另一台具有外网 IP 的服务器上运行 nginx,为内网服务器提供反向代理,允许从外部访问 MediaWiki。测试发现,通过反向代理访问一般页面没有问题,但对于返回 HTTP/1.1 404 的页面,HTML 头部和尾部分别出现了额外的字符。头部多出的是 2-4 位 16 进制数,如“355b”,尾部多出的总是“0”。而且这个现象只出现在 nginx 反向代理之后的页面,不出现在 Apache 原始页面。

使用 Wireshark 对比 nginx 和 Apache 的 respone,发现凡是出问题的页面,其传输方式均为 chunked(“Transfer-Encoding: chunked”)。查阅资料得知头部的 16 进制数(chunk 长度)、尾部的 0(chunk 终结)正是 chunked 传输方式的消息标识。Apache 的 respone 只有一个 chunk,而 nginx 的 respone 则分为 4 个 chunks,其中第 1 个 chunk 的头部、第 4 个 chunk 的尾部出现的额外字节正是 Apache 的 respone 中原始的 chunk 标识。看来,出现额外的字符是因为 nginx 对已经做过 chunked 的消息重复执行了 chunked 操作。

解决这个问题,只需要禁止 nginx 进行多余的 chunked 过程。经查,可以在 nginx 配置文件中相应网站的 location 段中加一行“chunked_transfer_encoding off;”。

location / {
  proxy_pass              http://10.0.0.10/;
  proxy_redirect          off;
  proxy_set_header        Host            $http_host;
  proxy_set_header        X-Real-IP       $remote_addr;
  proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
  chunked_transfer_encoding       off;
}

另外,也有人提供了 patch,更加智能地解决这个问题。