項目地址
https://github.com/yinjihuan/kitty-cloud
異常處理不用我講,大家都清楚。單獨的異常處理太繁瑣,全局異常處理可以在一個應用中統一進行異常的處理,非常方便。目前全局異常處理用的也越來越廣泛,今天跟大家來聊一聊 Kitty Cloud 中的全局異常是如何處理的?
為什么要使用全局異常處理呢?
使用全局異常處理后,我們不需要定義固定類型的返回值,當業務代碼報錯的時候直接通過異常處理方式來返回給前端或者 API 調用方錯誤信息。
不使用全局異常處理案例
Web 層
比如我們定義了一個 ResponseData 用來返回固定格式的數據,正常情況下不會有問題,給前端返回的格式也是固定的,如下:
{
"code":200,
"data":{
"name":"yinjihuan"
},
"message":"success",
}
如果業務發生異常,那么這個接口就不會返回上面那樣固定格式的數據了,會給我們返回錯誤頁面。除了代碼異常還有一種情況就是當訪問的 Uri 錯誤的時候,也會給調用方返回 404 的錯誤頁面,如下:
如果是傳統的 Web 項目,里面包含了頁面這是沒問題的,我們也可以自定義錯誤頁面讓用戶體驗更好一點。但是在這個基本上是前后端分離的開發模式下,后端只提供的數據的 API,不會有頁面的內容。所以就算出錯了,就算使用者調用的 API 路徑錯了,也應該返回固定的格式,並且告訴調用方路徑錯了。所以我們需要全局的異常處理。
業務層
在業務層最常見的用法就是我們可以直接拋出自定義異常,這樣在全局異常處理后給調用方返回的還是固定的格式,如果沒有全局異常處理,我們可能會用固定的 Response 來做這件事,比如下面的代碼:
public Response createOrder(CreateOrderParam param) {
Response checkResponse = paramsCheck(param);
if (!checkResponse.isSuccess()) {
return checkResponse();
}
...........
}
private Response paramsCheck(CreateOrderParam param) {
if (param.getTotalPrice() <= 0){
return Response.fail("金額錯誤");
}
if (param.getGoodsCount() <= 0){
return Response.fail("數量錯誤");
}
return Response.success();
}
當我們有了全局異常處理后,這邊就直接可以拋出自定義的異常了,代碼看起來會簡潔一些。
public Response createOrder(CreateOrderParam param) {
paramsCheck(param);
...........
}
private void paramsCheck(CreateOrderParam param) {
if (param.getTotalPrice() <= 0){
throw new BizException(
ResponseCode.PARAM_ERROR_CODE, "金額錯誤");
}
if (param.getGoodsCount() <= 0){
throw new BizException(
ResponseCode.PARAM_ERROR_CODE, "數量錯誤")
}
}
業務層的異常跑出去后,在全局異常中會進行處理成固定的格式,然后返回給調用方。像很多開放平台的 API 都會有很多的 code 來表示不同的異常類型。
內部服務層
內部服務層也就是說內部服務之間的調用,比如我們用 Dubbo, 如果被調用的服務中沒有進行全局異常處理,那么當調用的某個接口報錯的時候,調用者這邊就會直接報錯。
如果我們想就算報錯了,調用方這邊還是能夠獲取到正常的響應內容,只不過是內容中會告訴我這個請求是成功的還是失敗的。
比如下面的遠程調用,如果有全局異常處理,那么就可以根據響應判斷是否成功,如果沒有的話就直接報錯了,如果需要對錯誤進行處理,還得捕獲異常進行處理。
ResponseData<UserResponse> user =
userRemoteService.getUser(userId);
if(user.isSuccess()) {
.......
}
全局異常處理
Http 全局異常處理
關於 Http 的全局異常處理,這邊就不細講了,大家可以查看我的這篇文章:https://mp.weixin.qq.com/s/sIkrZTzGP4caKHzKYKqT7A
處理后如果有報錯,那么返回的也是固定的數據格式:
{
code: 500,
message: "/ by zero",
data: null,
domain: "kitty-cloud-article-provider",
errors: null,
requestId: "52a9f30323e80d82",
success: false
}
Rpc(Dubbo)全局異常處理
Dubbo 的全局異常處理可以通過 Filter 進行處理,獲取執行的結果去進行處理,如果有異常信息就將相應的內容改成統一的失敗格式進行返回。
需要注意的是要將 Result 中的 Exception 設置為 null, 因為 Dubbo 內部的 org.apache.dubbo.rpc.filter.ExceptionFilter 也會對異常進行處理,移除掉后 ExceptionFilter 就不會執行對應的邏輯了。
Dubbo 處理后的效果也是會返回固定格式,如下: