HttpClient異常處理手冊

開源中國
異常處理
HttpClient的使用者在執行HTPP方法(GET,PUT,DELETE等),可能遇到會兩種主要類型的異常:
- 傳輸異常
- 協議異常
並不是所有的異常都會傳播給HttpClient的用戶。HttpClient內部使用的異常在下文中將會標記為內部使用
- 傳輸異常
- 協議異常
- HTTP傳輸安全
- 自動異常恢復
- 自定義異常處理
傳輸異常
傳輸異常都是諸如不可靠的連接到輸入/輸出失敗或者未能在給與的時間內執行完HTPP方法(套接字超時)。一般來說,傳輸異常是非致命的錯誤,通過多次執行方法能夠恢復。在非幕等方法中恢復特別需要注意(詳細信息請參考HTTP傳輸安全)。
java.io.IOException
HttpCinet一般的傳輸異常可以用標准JAVA中 java.io.IOException或者其子類java.net.SocketException,java.net.InterruptedIOException來表示。
為了規划化輸入/輸出異常類,HttpClient定義多種自定義傳輸異常用來傳遞HttpClient特定的信息。
org.apache.commons.httpclient.NoHttpResponseException java.io.IOException +- org.apache.commons.httpclient.NoHttpResponseException
在某些情況下,由於服務器負載過大,服務器能接受到請求,但是沒有能力去處理,像工作線程這樣限制性資源就是一個很少的例子。這可能會導致服務器丟棄與客戶端的連接,而不會給予任何回應。HttpClient遭遇這種情況時,拋出NoHttpResponseException 。在多數情況下,通過重試能夠從此異常中恢復。
org.apache.commons.httpclient.ConnectTimeoutException java.io.IOException +- java.io.InterruptedIOException
這種異常表示在給定的時間HttpClient與目標服務器或代理服務器建立起連接。
org.apache.commons.httpclient.ConnectionPoolTimeoutException
- java.io.IOException
- +- java.io.InterruptedIOException
- +- org.apache.commons.httpclient.ConnectTimeoutException
- +- org.apache.commons.httpclient.ConnectionPoolTimeoutException
只有在使用多線程連接管理器時,才可能發生此異常。此異常表示在給定的時間從連接池中獲取一個空閑連接失敗。
org.apache.commons.httpclient.HttpRecoverableException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.HttpRecoverableException
廢棄,任何標准HttpClient類中不會拋出此異常。
協議異常
在HTTP規范的解釋中,協議異常通常是由客戶端與服務器(web服務器或是代理服務器)的不匹配導致的邏輯錯誤。如果不對客戶端的請求或服務器做出調整,HttpClient此異常不能恢復。HTTP規范的多個方面允許不同甚至是相互沖突的解釋。HttpClient能偶采用配置來支持從非常寬松到非常嚴格的HTTP規范的遵從度。
org.apache.commons.httpclient.HttpException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
HttpException在HttpClient中代表一個抽象邏輯錯誤,一般情況下,程序不能從這種錯誤中恢復。
org.apache.commons.httpclient.ProtocolException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.ProtocolException
ProtocolException表示一個HTTP規范的沖突,值得注意的是HTTP代理服務器和HTTP服務器有着不同的HTTP規范的支持度級別。通過配置HttpClient更寬松可以讓程序從非致命的協議沖突的HTTP協議異常恢復。
org.apache.commons.httpclient.auth.MalformedChallengeException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.ProtocolException
- +- org.apache.commons.httpclient.auth.MalformedChallengeException
內部使用
MalformedChallengeException表示一個身份認證憑證的某些方面在給定的身份認證的上下文中是無效或者非法的。
org.apache.commons.httpclient.auth.AuthenticationException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.ProtocolException
- +- org.apache.commons.httpclient.auth.AuthenticationException
內部使用
AuthenticationException用來表示身份認證過程中的失敗。通常,認證異常不會傳遞給調用者,只在內部處理使用。
org.apache.commons.httpclient.auth.AuthChallengeException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.ProtocolException
- +- org.apache.commons.httpclient.auth.AuthenticationException
- +- org.apache.commons.httpclient.auth.AuthChallengeException
內部使用
HttpClient無法響應服務器發送的任何身份驗證質詢時,AuthenticationException將會拋出。
org.apache.commons.httpclient.auth.CredentialsNotAvailableException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.ProtocolException
- +- org.apache.commons.httpclient.auth.AuthenticationException
- +- org.apache.commons.httpclient.auth.CredentialsNotAvailableException
內部使用
CredentialsNotAvailableException表明響應身份驗證質詢的要求的證書不可用。
org.apache.commons.httpclient.auth.InvalidCredentialsException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.ProtocolException
- +- org.apache.commons.httpclient.auth.AuthenticationException
- +- org.apache.commons.httpclient.auth.InvalidCredentialsException
內部使用
InvalidCredentialsException表明響應身份驗證質詢的要求的證書被服務器拒絕。
org.apache.commons.httpclient.cookie.MalformedCookieException
java.io.IOException
+- org.apache.commons.httpclient.HttpException
+- org.apache.commons.httpclient.ProtocolException
+- org.apache.commons.httpclient.cookie.MalformedCookieException
內部使用
MalformedCookieException表示cookie的某些方面在給定的HTTP會話上下文中是無效或者非法的。有多種不兼容cookie規范,因此,cookie合法性建立在用於分析的特定cookie規范的上下文中和驗證服務器發送cookie頭消息。如果應用程序需要處理不常見的cookie規范定義的cookie,請查看cookie文檔獲取更多的信息。
org.apache.commons.httpclient.RedirectException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.ProtocolException
- +- org.apache.commons.httpclient.RedirectException
RedirectException表示一個無效的重定向響應導致了HTTP規范沖突。如果使用HttpClient的應用程序就重定向需要更多的寬松度的話,它可以選擇禁用自動重定向處理和實現自定義重定向策略。
org.apache.commons.httpclient.URIException
- java.io.IOException
- +- org.apache.commons.httpclient.HttpException
- +- org.apache.commons.httpclient.URIException
URIException表示請求的URL不符合URI規范。
HTTP傳輸安全
有必要了解是HTTP協議並不適用於所有類型的應用程序。HTTP是一個簡單的面向requestre/sponse的協議,協議最初設計為支持靜態或動態生成的內容檢索。它從未打算支持事務性操作。例如,如果HTTP服務器成功接收和處理該請求,HTTP服務器會考慮其履行契約的一部分,生成響應和發送狀態碼回客戶端。如果客戶端由於讀取超時,請求取消,或者系統崩潰而導致讀取整個響應失敗,服務器將不試圖回滾事務。如果客戶端重新發送同一請求,服務器將最終無可避免再一次執行同一事務。在某些情況下,將有可能導致應用程序數據的損壞或程序狀態的不一致。
即使HTTP從未被設計為支持事務性處理,它還是可以用作滿足某些條件關鍵應用程序傳輸協議。為確保HTTP傳輸層安全系統必須確保應用層上的HTTP方法是幕等的。
幕等方法
HTTP/1.1規范定義幕等方法為:
Methods can also have the property of"idempotence"in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
換句話說,應用程序應該確保它准備處理同一個的方法的多次執行帶來的影響。這可以做到的,例如,通過提供一個唯一的事務id和通過其他方式避免執行相同的邏輯操作。
需要注意的,這是問題並非特定於HttpClient。基於瀏覽器的應用程序在涉及到非幕等HTTP方法時,也會面臨同樣的問題。
自動異常恢復
默認情況下HttpClient嘗試從異常中自動恢復。默認的自動恢復機制僅限於少數的幾個已知安全的異常。HttpClient不會嘗試從任何邏輯或是HTTP協議錯誤(HttpException派生的異常類)中恢復。
HttpClient將最多5次自動重試因傳輸異常失敗的方法,雖然請求仍被傳輸到目標服務器(也就是說,請求尚未完全傳送到服務器)。
HttpClient將最多自動重試那些方法5次,直到請求完全傳送到服務器,但該服務器沒有響應的HTTP狀態代碼(服務器只是簡單的丟棄連接而沒有發回任何響應)。在這種情況下則假定請求未被服務器處理和應用程序狀態沒有改變。如果web服務器應用程序目標的假設不成立,那么極力建議您提供自定義的異常處理程序。
自定義異常處理類
為了啟用自定義異常的恢復機制應提供HttpMethodRetryHandler接口的實現。
HttpClient client = new HttpClient(); HttpMethodRetryHandler myretryhandler = new HttpMethodRetryHandler() { public boolean retryMethod( final HttpMethod method, final IOException exception, int executionCount) { if (executionCount >= 5) { // Do not retry if over max retry count return false; } if (exception instanceof NoHttpResponseException) { // Retry if the server dropped connection on us return true; } if (!method.isRequestSent()) { // Retry if the request has not been sent fully or // if it's OK to retry methods that have been sent return true; } // otherwise do not retry return false; } }; GetMethod httpget = new GetMethod("http://www.whatever.com/"); httpget.getParams(). setParameter(HttpMethodParams.RETRY_HANDLER, myretryhandler); try { client.executeMethod(httpget); System.out.println(httpget.getStatusLine().toString()); } finally { httpget.releaseConnection(); }