本文是精講RestTemplate第7篇,前篇的blog訪問地址如下:
- 精講RestTemplate第1篇-在Spring或非Spring環境下如何使用
- 精講RestTemplate第2篇-多種底層HTTP客戶端類別庫的切換
- 精講RestTemplate第3篇-GET請求使用方法詳解
- 精講RestTemplate第4篇-POST請求方法使用詳解
- 精講RestTemplate第5篇-DELETE、PUT等請求方法使用詳解
- 精講RestTemplate第6篇-檔案上傳下載與大檔案流式下載
一、例外現象
在使用RestTemplate進行遠程介面服務呼叫的時候,當請求的服務出現例外:超時、服務不存在等情況的時候(回應狀態非200、而是400、500HTTP狀態碼),就會拋出如下例外:

該例外我是模擬出來的,將正確的請求服務地址由“/posts/1”改成“/postss/1”,服務不存在所以拋出404例外,
@Test
public void testEntity() {
String url = "http://jsonplaceholder.typicode.com/postss/1";
ResponseEntity<String> responseEntity
= restTemplate.getForEntity(url, String.class); //這行拋出例外
//下面兩行代碼執行不到
HttpStatus statusCode = responseEntity.getStatusCode(); // 獲取回應碼
System.out.println("HTTP 回應狀態:" + statusCode);
}
例外拋出之后,程式后面的代碼就執行不到了,無法進行后面的代碼執行,實際的業務開發中,有的時候我們更期望的結果是:不管你服務端是超時了還是服務不存在,我們都應該獲得最終的請求結果(HTTP請求結果狀態400、500),而不是獲得一個拋出的例外,
二、原始碼決議-默認實作
首先我要說一個結論:RestTemplate請求結果例外是可以自定義處理的,在開始進行自定義的例外處理邏輯之前,我們有必要看一下例外處理的默認實作,也就是:為什么會產生上面小節提到的現象?
- ResponseErrorHandler是RestTemplate請求結果的例外處理器介面
- 介面的第一個方法hasError用于判斷HttpResponse是否是例外回應(通過狀態碼)
- 介面的第二個方法handleError用于處理例外回應結果(非200狀態碼段)
- DefaultResponseErrorHandler是ResponseErrorHandler的默認實作
所以我們就來看看DefaultResponseErrorHandler是如何來處理例外回應的?從HttpResponse決議出Http StatusCode,如果狀態碼StatusCode為null,就拋出UnknownHttpStatusCodeException例外,

如果StatusCode存在,則決議出StatusCode的series,也就是狀態碼段(除了200段,其他全是例外狀態碼),決議規則是StatusCode/100取整,
public enum Series {
INFORMATIONAL(1), // 1xx/100
SUCCESSFUL(2), // 2xx/100
REDIRECTION(3), // 3xx/100
CLIENT_ERROR(4), // 4xx/100 ,客戶端例外
SERVER_ERROR(5); // 5xx/100 ,服務端例外
}
進一步針對客戶端例外和服務端例外進行處理,處理的方法是拋出HttpClientErrorException,也就是第一小節出現的例外的原因

三、RestTemplate自定義例外處理
所以我們要實作自定義例外,實作ResponseErrorHandler 介面就可以,
public class MyRestErrorHandler implements ResponseErrorHandler {
/**
* 判斷回傳結果response是否是例外結果
* 主要是去檢查response 的HTTP Status
* 仿造DefaultResponseErrorHandler實作即可
*/
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
int rawStatusCode = response.getRawStatusCode();
HttpStatus statusCode = HttpStatus.resolve(rawStatusCode);
return (statusCode != null ? statusCode.isError(): hasError(rawStatusCode));
}
protected boolean hasError(int unknownStatusCode) {
HttpStatus.Series series = HttpStatus.Series.resolve(unknownStatusCode);
return (series == HttpStatus.Series.CLIENT_ERROR || series == HttpStatus.Series.SERVER_ERROR);
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// 里面可以實作你自己遇到了Error進行合理的處理
//TODO 將介面請求的例外資訊持久化
}
}
將MyRestErrorHandler 在RestTemplate實體化的時候進行注冊,參考: 《精講RestTemplate第1篇-在Spring或非Spring環境下如何使用》 和 《精講RestTemplate第2篇-多種底層HTTP客戶端類別庫的切換》 進行實作

這時再去執行第一小節中的示例代碼,就不會拋出例外,而是得到一個HTTP Status 404的結果,我們可以根據這個結果,在程式中繼續向下執行代碼,

歡迎關注我的博客,里面有很多精品合集
- 本文轉載注明出處(必須帶連接,不能只轉文字):字母哥博客,
覺得對您有幫助的話,幫我點贊、分享!您的支持是我不竭的創作動力! ,另外,筆者最近一段時間輸出了如下的精品內容,期待您的關注,
- 《手摸手教你學Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《實戰前后端分離RBAC權限管理系統》
- 《實戰SpringCloud微服務從青銅到王者》
- 《VUE深入淺出系列》
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/79308.html
標籤:Java
上一篇:Spring Boot 教程 - MyBatis-Plus
下一篇:Java并發---并發理論
