Hessian HTTP POST訪問時,Nginx返回411問題

猿碼道發表於2018-02-02

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 排查過程

  1. 不通過Nginx反向代理時,Hessian介面訪問正常;【正常】
  2. 檢視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 沒有這個問題。模組介紹和具體安裝過程見:wiki.nginx.org/HttpChunkin…,把這個模組編譯進去後給 server 節點新增一個配置就可以了:

server {
    chunkin on;
    error_page 411 = @my_411_error;
    location @my_411_error {
        chunkin_resume;
    }
}
複製程式碼

之後重啟nginx就可以了。

相關文章