上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。
Filter為二方包異常手動捕獲
參考:https://blog.csdn.net/2401_84048290/article/details/138105184
我們來看看dubbo的源碼進行分析,如果Dubbo的provider端 拋出異常(Throwable),則會被 provider端 的ExceptionFilter攔截到,執行以下invoke方法,裡面有個實現Listener類,重寫了onResponse,我們可以自定義filter來覆蓋原來的ExceptionFilter,把自定義的異常通過RuntimeException進行包裹,然後在Mapper中進行統一的捕獲。
- 添加CustomExceptionFilter類型,實現Filter和BaseFilter.Listener,重寫onResponse方法,添加自定義代碼,如下:
public class CustomExceptionFilter implements Filter, BaseFilter.Listener {
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
exception = appResponse.getException();
String className = exception.getClass().getName();
// 本項目的異常也直接拋出
if (className.startsWith("com.myself.")) {
appResponse.setException(new RuntimeException(exception));
return;
}
// 其它原來ExceptionFilter中的代碼
}
}
- META-INF中註冊這個過濾器resources/META-INF/dubbo/org.apache.dubbo.rpc.Filter
customExceptionFilter=com.xxx.register.exception.filter.CustomExceptionFilter
- 配置中文中註冊,並移除預設的resources/application.properties
# 自定義過濾器,上面-exception就是dubbo預設的處理異常的filter,前面-號就代表去除,註意:不需要加雙引號
dubbo.provider.filter=customExceptionFilter,-exception
一個Mapper處理所有自定義異常
- 配置文件中指定mapper,resources/application.properties
dubbo.protocols.http.extension=com.xxx.register.exception.mapper.CustomExceptionMapper
- mapper源碼如下
@Provider
public class DbViolationExceptionMapper implements ExceptionMapper<RuntimeException> {
@Override
public Response toResponse(RuntimeException exception) {
Map<String, String> map = MapUtil.<String, String>builder().put("error", exception.getMessage()).build();
if (exception.getCause() instanceof ForbiddenException) {
return Response.status(Response.Status.FORBIDDEN).entity(map).type(MediaType.APPLICATION_JSON).build();
}
if (exception.getCause() instanceof CustomException) {
return Response.status(Response.Status.BAD_REQUEST).entity(map).type(MediaType.APPLICATION_JSON).build();
}
if (exception.getCause() instanceof IdentityBrokerException) {
return Response.status(Response.Status.UNAUTHORIZED).entity(map).type(MediaType.APPLICATION_JSON).build();
}
if (exception.getCause() instanceof UniqueException) {
return Response.status(Response.Status.SERVICE_UNAVAILABLE).entity(map).type(MediaType.APPLICATION_JSON)
.build();
}
return Response.status(Response.Status.SERVICE_UNAVAILABLE)
.entity(MapUtil.builder().put("error", exception.getMessage()).build()).type(MediaType.APPLICATION_JSON)
.encoding("utf-8").build();// 非200的請求,這個type無效,一直是text/plain
}
}
未解決的問題
- 目前非200的請求,toResponse時,響應類型還是text/plain
作者:倉儲大叔,張占嶺,
榮譽:微軟MVP
QQ:853066980
支付寶掃一掃,為大叔打賞!