2012-02-06 23 views
4

我正在開發和測試一個使用java(和scala)的簡單直觀的客戶端 - 服務器應用程序。Apache HttpClient 4.x在上傳較大的文件時表現奇怪?

服務器基於com.sun.net.httpserver.HttpServer,允許使用POST和PUT操作通過基本RESTful接口上傳文件。使用我們自己實現的Digest authentication來限制上傳操作,並且在瀏覽器,捲曲和Apache HttpClient中進行測試和工作。

上傳客戶端包裝Apache HttpClient 4.1.2並通過http執行PUT操作以上傳文件實體。該文件的內容類型在標題中指定爲application/xml,並且一次只上傳一個文件。

當上傳不同尺寸可以觀察到一個奇怪的行爲的文件:

  • 文件與尺寸小於或等於1.076.006字節被上傳 成功
  • 文件大小大於或等於1.122.158字節 失敗java.net.SocketException: Broken pipe

準確的臨界大小是未知的,因爲我已經創建的文件大小不同的人工逼近最大工作尺寸

之所以破裂的管道是,客戶端因爲某種忽略www-authenticate -response上傳該大小的文件,這是由服務器日誌記錄的。 「忽略」意味着它只發送多個(4)消息,其中不包含任何驗證頭。 但是較小的文件工作良好,客戶端在www-authenticate響應之後立即正確發送具有正確質詢 - 響應的認證請求,因爲它應該是。

上傳工作捲曲與所有大小的文件,所以沒有問題。

因此,在這一點上,可以說:「您的客戶端存在一些錯誤。」好吧,我有點希望,但我也試過一個開源的java RESTclient(也包裝apache httpclient),它有正好相同的行爲!

我們在互聯網上使用此客戶端進行了試用,其描述與上述相同。所以現在,我只希望我錯過了在Apache HttpClient中設置一些重要的東西,這會導致這種錯誤的行爲,而開源RESTclient的開發人員也錯過了它......任何想法都可能會很棒!

回答

6

它最有可能是幾個因素的結合,導致這種情況

(1)最有可能你的客戶不使用「期望繼續」用未請求發送大量請求的實體時握手包含一個驗證標題。(2)服務器儘早檢測到請求不符合期望,而不是讀取並丟棄完整的請求體,它以401狀態提前響應,並在其結束時關閉連接。在我看來,這是服務器部分違反HTTP協議的原因。 (3)儘管一些HTTP代理可以處理早期響應,但由於Java阻塞I/O的限制,Apache HttpClient不能實現(一個執行線程可以從阻塞套接字讀取或寫入數據,但不能同時使用兩者) 。

解決這個問題有多種方式,'expect-continue'握手是最簡單也是最自然的握手方式。或者,可以執行簡單的HEAD或GET請求,以在執行大量POST或PUT請求之前強制進行HTTP身份驗證。 HttpClient能夠在相同的邏輯HTTP會話中爲後續請求重新使用身份驗證數據。

+0

感謝您的解釋,它非常有意義!現在我去尋求'繼續'的解決方案。在客戶端它只是翻轉一個布爾值。現在服務器握手正在進行中,我相信這應該可以解決問題。 – mtsz 2012-02-07 17:09:07

+0

奇怪的是,底層的sun httpserver *始終*以100次繼續響應,而不涉及應用程序!在我看來,它違反了協議(請參閱RFC 2616「使用100(繼續)狀態」,httpserver-source:http://www.docjar.com/html/api/sun/net/httpserver/ServerImpl。 java.html)。但是在發送大量數據之前,我已經使用第二個請求實現了第二個解決方案觸發身份驗證。這工作,所以非常感謝! – mtsz 2012-02-08 15:12:16

+0

@mtsz這不關我的事,但爲什麼現在有這麼多像樣的嵌入式HTTP服務器時,你一直在使用Sun的ServerImpl? – oleg 2012-02-08 15:46:14

相關問題