1 問題描述
用 Hessian 實現(xiàn) web service 過程中嫂冻,需要創(chuàng)建對象時珠叔,是使用 HTTP POST 方法來傳遞數(shù)據(jù)的氓扛。但是在有反向代理 (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 服務(wù)器不能處理請求,除非客戶發(fā)送一個 Content-Length 頭奏司。( HTTP 1.1 新)這是因為 Hessian 與服務(wù)端通信默認是采取分塊的方式 (chunked encoding) 發(fā)送數(shù)據(jù)瓷叫,而反向代理要獲得 Content-Length 這個頭,才能處理請求楞陷,但是 Hessian 的請求中并沒有加入這個參數(shù)怔鳖。
2 排查過程
- 不通過Nginx反向代理時,Hessian接口訪問正常固蛾;【正辰嶂矗】
- 查看Nginx的日志access.log,是有Nginx返回411狀態(tài)艾凯;【不正诚揍#】
3 解決問題
com.caucho.hessian.client.HessianProxyFactory 類中,有一個 boolean _chunckedPost 的域成員趾诗,其默認值為 true 蜡感。這個值就是規(guī)定 Hessian 是否以分塊發(fā)送的方式與服務(wù)端交換數(shù)據(jù)的參數(shù),因此在創(chuàng)建 com.caucho.hessian.client.HessianProxyFactory 的對象后(假設(shè)為 factory )恃泪,只要調(diào)用其上的 setChunckedPost() 方法郑兴,把這個屬性設(shè)置為 false 即可。即 factory.setChunkedPost(false);
4 問題總結(jié)
分塊編碼 (chunked encoding) 傳輸方式 是 HTTP 1.1 協(xié)議中定義的 Web 用戶向服務(wù)器提交數(shù)據(jù)的一種方法贝乎,當服務(wù)器收到 chunked 編碼方式的數(shù)據(jù)時會分配一個緩沖區(qū)存放之情连,如果提交的數(shù)據(jù)大小未知,客戶端會以一個協(xié)商好的分塊大小向服務(wù)器提交數(shù)據(jù)览效。
如果不使用 Chunked encoding 傳輸方式蒙具,需要將要發(fā)送的數(shù)據(jù)緩存下來,計算出 content-length 朽肥,從而滿足反向代理( Nginx )需要 content-length 的要求禁筏。
該問題還可以通過修改 nginx 配置,使得 nginx 可以處理分塊編碼 (chunked encoding) 傳輸方式衡招。在使用Nginx 1.3.9以下版本篱昔,都存在當用戶POST一個帶有文件的請求的時候,出現(xiàn)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 解決浪箭。由于這個模塊已經(jīng)內(nèi)置到了 nginx 1.3.9 以后的 nginx 核心了穗椅,所以原來的 nginx 1.4.x 沒有這個問題。模塊介紹和具體安裝過程見:http://wiki.nginx.org/HttpChunkinModule奶栖,把這個模塊編譯進去后給 server 節(jié)點添加一個配置就可以了:
server {
chunkin on;
error_page 411 = @my_411_error;
location @my_411_error {
chunkin_resume;
}
}
之后重啟nginx就可以了匹表。