異常處理 java
HttpClient的使用者在執行HTPP方法(GET,PUT,DELETE等),可能遇到會兩種主要類型的異常:web
- 傳輸異常
- 協議異常
並非全部的異常都會傳播給HttpClient的用戶。HttpClient內部使用的異常在下文中將會標記爲內部使用apache
- 傳輸異常
- 協議異常
- HTTP傳輸安全
- 自動異常恢復
- 自定義異常處理
傳輸異常 瀏覽器
傳輸異常都是諸如不可靠的鏈接到輸入/輸出失敗或者未能在給與的時間內執行完HTPP方法(套接字超時)。通常來講,傳輸異常是非致命的錯誤,經過屢次執行方法可以恢復。在非幕等方法中恢復特別須要注意(詳細信息請參考HTTP傳輸安全)。 安全
java.io.IOException 服務器
HttpCinet通常的傳輸異常能夠用標準JAVA中 java.io.IOException或者其子類java.net.SocketException,java.net.InterruptedIOException來表示。 cookie
爲了規劃化輸入/輸出異常類,HttpClient定義多種自定義傳輸異經常使用來傳遞HttpClient特定的信息。 多線程
org.apache.commons.httpclient.NoHttpResponseException java.io.IOException +- org.apache.commons.httpclient.NoHttpResponseException
在某些狀況下,因爲服務器負載過大,服務器能接受到請求,可是沒有能力去處理,像工做線程這樣限制性資源就是一個不多的例子。這可能會致使服務器丟棄與客戶端的鏈接,而不會給予任何迴應。HttpClient遭遇這種狀況時,拋出NoHttpResponseException 。在多數狀況下,經過重試可以今後異常中恢復。 ide
org.apache.commons.httpclient.ConnectTimeoutException java.io.IOException +- java.io.InterruptedIOException
這種異常表示在給定的時間HttpClient與目標服務器或代理服務器創建起鏈接。 spa
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(); }