上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常新增自己的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