1 问题描述
用 Hessian 实现 web service 过程中,需要创建对象时,是使用 HTTP POST 方法来传递数据的。但是在有反向代理 (nginx) 的情况下,会抛出异常
(com.caucho.hessian.client.HessianConnectionException: 411:java.io.IOException: Server returned HTTP response code: 411 for URL:http://xxxx/xxx/xxxService) 。
首先来看下 HTTP 411 错误的解释: Length Required 服务器不能处理请求,除非客户发送一个 Content-Length 头。( HTTP 1.1 新)这是因为 Hessian 与服务端通信默认是采取分块的方式 (chunked encoding) 发送数据,而反向代理要获得 Content-Length 这个头,才能处理请求,但是 Hessian 的请求中并没有加入这个参数。
2 排查过程
- 不通过Nginx反向代理时,Hessian接口访问正常;【正常】
- 查看Nginx的日志access.log,是有Nginx返回411状态;【不正常】
3 解决问题
com.caucho.hessian.client.HessianProxyFactory 类中,有一个 boolean _chunckedPost 的域成员,其默认值为 true 。这个值就是规定 Hessian 是否以分块发送的方式与服务端交换数据的参数,因此在创建 com.caucho.hessian.client.HessianProxyFactory 的对象后(假设为 factory ),只要调用其上的 setChunckedPost() 方法,把这个属性设置为 false 即可。即 factory.setChunkedPost(false);
4 问题总结
分块编码 (chunked encoding) 传输方式 是 HTTP 1.1 协议中定义的 Web 用户向服务器提交数据的一种方法,当服务器收到 chunked 编码方式的数据时会分配一个缓冲区存放之,如果提交的数据大小未知,客户端会以一个协商好的分块大小向服务器提交数据。
如果不使用 Chunked encoding 传输方式,需要将要发送的数据缓存下来,计算出 content-length ,从而满足反向代理( Nginx )需要 content-length 的要求。
该问题还可以通过修改 nginx 配置,使得 nginx 可以处理分块编码 (chunked encoding) 传输方式。在使用Nginx 1.3.9以下版本,都存在当用户POST一个带有文件的请求的时候,出现HTTP 411错误。 这个是Nginx的问题,需要打一个补丁。
#下载chunkin模块
git clone https://github.com/agentzh/chunkin-nginx-module.git
#编译nginx,使用chunkin模块
wget http://nginx.org/download/nginx-1.2.7.tar.gz
tar xvzf nginx-1.2.7.tar.gz
cd nginx-1.2.7
./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_gzip_static_module --with-google_perftools_module --with-http_realip_module --add-module=../chunkin-nginx-module
make -j8
make install
添加 HttpChunkinModule 解决。由于这个模块已经内置到了 nginx 1.3.9 以后的 nginx 核心了,所以原来的 nginx 1.4.x 没有这个问题。模块介绍和具体安装过程见:http://wiki.nginx.org/HttpChunkinModule,把这个模块编译进去后给 server 节点添加一个配置就可以了:
server {
chunkin on;
error_page 411 = @my_411_error;
location @my_411_error {
chunkin_resume;
}
}
之后重启nginx就可以了。
网友评论