SpringCloud feign微服務(wù)調(diào)用之間的異常處理方式
如何優(yōu)雅地處理微服務(wù)間調(diào)用的異常
現(xiàn)在微服務(wù)架構(gòu)盛行,其中spring cloud方案就很具有代表。
那么在微服務(wù)之間進(jìn)行調(diào)用,如果被調(diào)用的服務(wù)掛了,調(diào)用方如何感知呢?
一、加上hystrix熔斷
在定義feignClient的地方指定熔斷,如下圖
當(dāng)被調(diào)用服務(wù)不可用或者被調(diào)用方發(fā)生錯(cuò)誤的時(shí)候,會(huì)觸發(fā)熔斷,但是,如果被調(diào)用方拋出異常,調(diào)用方怎么知道究竟是出了什么問題呢?
那,這就出現(xiàn)了
二、feign全局異常處理
我們不得不提到feign提供的一個(gè)接口叫做ErrorDecoder, 是用來處理feign異常的,有一個(gè)方法需要實(shí)現(xiàn) public Exception decode(String s, Response response)
如下圖:
這樣就會(huì)替換它默認(rèn)的feign異常處理,這樣就可以捕捉全局的異常了,但是又帶來一個(gè)新的問題,如果使用這個(gè)ErrorDecoder,得關(guān)閉熔斷,否者這里拋出的FeignBadRequestException異常又會(huì)被hystrix吞掉,那,有沒有更好的辦法呢?
在被調(diào)用的controller方法里面捕捉全局異常,發(fā)生錯(cuò)誤的時(shí)候,把異常保存一個(gè)對象里面,然后用該對象進(jìn)行服務(wù)間的通信,調(diào)用方收到結(jié)果再檢查是否包含錯(cuò)誤,這個(gè)方式確實(shí)可以解決,但,這肯定不是個(gè)好辦法;那么有沒有更好的辦法呢?跳出ErrorDecoder后,會(huì)經(jīng)過在AbstractCommand里面的一個(gè)executeCommandAndObserve方法里面有個(gè)function叫做 handleFallback
由此可知,當(dāng)拋出的異常是HystrixBadRequestException時(shí),直接拋出異常,不再經(jīng)過fallback,那么我們的解決辦法就有了,那就是調(diào)整FeignBadRequestException 的繼承對象,如圖
現(xiàn)在,就實(shí)現(xiàn)了服務(wù)端不可用和服務(wù)端報(bào)錯(cuò)的異常分離,但是可能,有的同學(xué)已經(jīng)注意到了,F(xiàn)eignClientErrorDecoder這個(gè)異常處理類里面是是針對狀態(tài)為SERVICE_UNAVAILABLE的進(jìn)行了特別處理,為社么要這樣?這是因?yàn)榕c被調(diào)用方約定當(dāng)狀態(tài)碼為 SERVICE_UNAVAILABLE 的時(shí)候視為被調(diào)用方主動(dòng)拋出的異常
需要注意的地方
我們的被調(diào)用方除了提供微服務(wù)之間調(diào)用,很可能也提供了面向前端的接口,為了封裝我們程序內(nèi)部的異常,通常我們會(huì)定義個(gè)全局異常捕捉類,即使報(bào)錯(cuò)了,我們也提供一個(gè)友好的交互方式,比如下面這樣
第一處我們除了系統(tǒng)內(nèi)部拋出的異常,第二處處理其它異常,也就是說,不管拋出什么錯(cuò),該服務(wù)都會(huì)返回一個(gè)狀態(tài)值為200的信息出去,那么問題來了,我們微服務(wù)間的調(diào)用也會(huì)被處理成200,從而導(dǎo)致feign會(huì)以為服務(wù)是正常的,正常返回結(jié)果了,沒有報(bào)錯(cuò),那怎么辦?
三、針對內(nèi)部調(diào)用的特殊處理
當(dāng)然,你可能想到了,我們可以在提供給內(nèi)部使用的接口進(jìn)行異常轉(zhuǎn)換,然后讓全局異常處理處不進(jìn)行這樣的處理,但是,每個(gè)內(nèi)部接口都要進(jìn)行全局異常捕捉,然后轉(zhuǎn)換,這,明顯不是最好的做法
四、通過注解標(biāo)記為接口為內(nèi)部調(diào)用接口
先定義一個(gè)注解,直接上圖
我們定義該注解為方法和類上都可以使用,然后再定義處理程序
處理程序要做一件事情,就是在程序方法異常的時(shí)候,將http狀態(tài)碼設(shè)置為我們約定的SERVICE_UNAVAILABLE,然后看下怎么使用
這樣我們把該方法標(biāo)記為了供內(nèi)部使用的接口,當(dāng)然,同樣也可以將注解放在類上,這樣就可以把該類的全部方法標(biāo)記為內(nèi)部調(diào)用。
至此,我們現(xiàn)在調(diào)用其它服務(wù)的方法,就可以調(diào)用本地的一樣了,當(dāng)然,如果你想在調(diào)用其它服務(wù)的方法報(bào)錯(cuò)后想繼續(xù)執(zhí)行其它邏輯,同樣也可以,直接catch FeignBadRequestException 這個(gè)異常就可以了
微服務(wù)間調(diào)用異常改參
兩個(gè)微服務(wù)之間通過feign調(diào)用時(shí),后臺(tái)拋出異常:
feign.RetryableException: Read timed out executing POST
解決方法:
在你的yml文件中添加
ribbon: ReadTimeout: 60000 ConnectTimeout: 60000
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Spring?Cloud?Alibaba?Nacos服務(wù)治理平臺(tái)服務(wù)注冊、RestTemplate實(shí)現(xiàn)微服務(wù)之間訪問負(fù)載均衡訪問的問題
- Spring Cloud多個(gè)微服務(wù)之間調(diào)用代碼實(shí)例
- spring cloud eureka微服務(wù)之間的調(diào)用詳解
- springcloud gateway如何實(shí)現(xiàn)路由和負(fù)載均衡
- Spring Cloud 負(fù)載均衡器 Ribbon原理及實(shí)現(xiàn)
- spring cloud 之 客戶端負(fù)載均衡Ribbon深入理解
- Spring Cloud實(shí)現(xiàn)微服務(wù)調(diào)用的負(fù)載均衡(詳解)
相關(guān)文章
springBoot啟動(dòng)時(shí)讓方法自動(dòng)執(zhí)行的幾種實(shí)現(xiàn)方式
這篇文章主要介紹了springBoot啟動(dòng)時(shí)讓方法自動(dòng)執(zhí)行的幾種實(shí)現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03eclipse怎么引入spring boot項(xiàng)目插件的方法
這篇文章主要介紹了eclipse怎么引入spring boot項(xiàng)目插件的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06Java數(shù)據(jù)結(jié)構(gòu)之KMP算法詳解以及代碼實(shí)現(xiàn)
KMP算法是一種改進(jìn)的字符串匹配算法,核心是利用之前的匹配失敗時(shí)留下的信息,選擇最長匹配長度直接滑動(dòng),從而減少匹配次數(shù)。本文主要介紹了KMP算法的原理與實(shí)現(xiàn),需要的可以參考一下2022-12-12Spring Boot JPA中java 8 的應(yīng)用實(shí)例
這篇文章主要介紹了Spring Boot JPA中java 8 的應(yīng)用實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02教你使用eclipse?搭建Swt?環(huán)境的全過程
本文給大家分享使用eclipse?搭建Swt?環(huán)境的全過程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12