本文是精講回應式WebClient第5篇,前篇的blog訪問地址如下:
- 精講回應式webclient第1篇-回應式非阻塞IO與基礎用法
- 精講回應式WebClient第2篇-GET請求阻塞與非阻塞呼叫方法詳解
- 精講回應式WebClient第3篇-POST、DELETE、PUT方法使用
- 精講回應式WebClient第4篇-檔案上傳與下載
本文來為大家介紹一下,當WebClient請求發生例外的時候,該如何處理,為了講解例外處理,我們需要先制造出例外,所以我們先為大家介紹:請求超時時長的設定,
一、請求超時時長的設定
要想模擬超時例外,我們首先要知道超時時長的正常配置渠道是怎么樣的,如下文代碼所示:
ChannelOption.CONNECT_TIMEOUT_MILLIS用來設定連接超時時長,單位是毫秒ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS)用來設定讀資料超時時長,單位是毫秒WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS)用來設定寫資料超時時長,單位是毫秒
//初始化一個WebClient
private WebClient getWebClient(){
TcpClient tcpClient = TcpClient
.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.doOnConnected(connection -> {
connection.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS));
connection.addHandlerLast(new WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS));
});
return WebClient.builder()
.baseUrl("http://jsonplaceholder.typicode.com")
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient)))
.build();
}
當我們把連接超時時長設定為5(毫秒)的時候,則連接肯定會超時,隨便發送一個請求,超時之后會拋出ConnectTimeoutException

當我們把讀資料超市時長設定為5(毫秒)的時候,則資料讀操作肯定會超時,隨便發送一個請求,超時之后會拋出ReadTimeoutException

二、處理特定的例外
下面我們就以ConnectTimeoutException為例,進行例外處理
//制造例外,將超時時間設定為5毫秒
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5)
然后執行下面的GET請求,上文WebClient的baseurl為:"http://jsonplaceholder.typicode.com" ,該網站是一個免費提供HTTP服務端測驗的網站,
@Test
public void testSimple() throws Exception {
Mono<String> mono = getWebClient()
.get() // 發送GET 請求
.uri("/posts/1") //服務請求路徑,基于baseurl
.retrieve() // 獲取回應體
.bodyToMono(String.class) //回應資料型別轉換
//進行例外處理
.doOnError(ConnectTimeoutException.class, err -> {
System.out.println("發生錯誤:" +err.getMessage() );
});
System.out.println(mono.block());
}
上文中的doOnError是我們本節為大家介紹的例外處理方法,用于處理ConnectTimeoutException,輸出結果如下:

從輸出結果上看:一:例外得到處理,因為看到了System.out列印日志,二是例外仍然被拋出了,沒有得到回傳值,
三、請求例外給出默認回傳值
從第二小節中的代碼及控制臺輸出,可以看出HTTP 客戶端請求沒有得到回傳值,而是繼續把例外對外拋出,假如我們目前的需求是,不論請求成功失敗,都給客戶端一個回傳值,該怎么做?也就是說我們需要在請求發生例外的時候,給出默認回傳值,
@Test
public void testReturn() throws Exception {
Mono<String> mono = getWebClient()
.get() // 發送GET 請求
.uri("/posts/1") //服務請求路徑,基于baseurl
.retrieve() // 獲取回應體
.bodyToMono(String.class) //回應資料型別轉換
.doOnError(ConnectTimeoutException.class, err -> {
System.out.println("發生錯誤:" +err.getMessage() );
})
.onErrorReturn("請求發生例外,請檢查!");
System.out.println(mono.block());
}
使用onErrorReturn();給出請求的默認回傳值,輸出結果如下:

可以看到請求測驗用例成功pass了,因為我們給出了例外處理的默認回傳值,沒有把例外繼續拋出,
四、分類例外處理
上面的例外處理方法,只能處理指定的某種例外:ConnectTimeoutException,如果說我們想讓例外處理相對通用一些該怎么辦?有的小伙伴可能會想到攔截例外的父類Exception,當然這也是一種辦法,
.doOnError(Exception.class, err -> {
System.out.println("發生錯誤:" +err.getMessage() );
});
我們下面為大家介紹一種,針對HTTP 回應例外處理更友好的一種方式,通常來說,例外可以分為兩種:
- 一種是客戶端輸入或訪問例外,比如:訪問的資源不存在404,沒有權限訪問資源403,輸入的資料不符合格式等等,這種例外通常是用戶訪問了不該訪問的資源,或者輸入了不該輸入的資料導致的,通常用HTTP狀態碼表示在400-499范圍內,
- 另一種是服務端內部錯誤,比如:500服務內部錯誤、502網關錯誤等等,這種例外通常和用戶沒什么關系,是IT基礎設施或者編程導致的例外,
所以我們只需要針對上面的兩類例外進行處理即可,如下文代碼所示:
- e.is4xxClientError()表示的是400-499狀態碼段的例外
- e.is5xxClientError()表示的是500-599狀態碼段的例外
public void testSimple2() throws Exception {
Mono<String> mono = getWebClient()
.get() // 發送GET 請求
.uri("/postss/1") //服務請求路徑,基于baseurl
.retrieve() // 獲取回應體
.onStatus(e -> e.is4xxClientError(), resp -> {
System.out.println("發生客戶端輸入錯誤:" + resp.statusCode().value() + " "
+ resp.statusCode().getReasonPhrase());
return Mono.error(new RuntimeException("請求失敗"));
})
.onStatus(e -> e.is5xxServerError(), resp -> {
System.out.println("發生服務端錯誤:" + resp.statusCode().value() + " "
+ resp.statusCode().getReasonPhrase());
return Mono.error(new RuntimeException("服務器例外"));
})
.bodyToMono(String.class); //回應資料型別轉換
System.out.println(mono.block());
}
現在我們將請求地址由正確的"/posts/1",改成錯誤的"/postss/1",所以當我們訪問服務端的時候,服務端并不存在這個資源,例外處理的輸出結果如下:

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