異常攔截器ExceptionMapper
在JAX-RS(Java API for RESTful Web Services)中,ExceptionMapper介面用於將Java異常對映到HTTP響應。透過實現ExceptionMapper介面,你可以自定義如何處理特定型別的異常,並生成相應的HTTP響應。
優先順序和選擇
當有多個ExceptionMapper可用於處理同一型別的異常時,JAX-RS會選擇最具體的那個。例如,如果你有一個處理RuntimeException的ExceptionMapper和一個處理NullPointerException的ExceptionMapper,那麼當丟擲NullPointerException時,會選擇處理NullPointerException的ExceptionMapper。
定義自定義異常
public class UniqueException extends RuntimeException {
public UniqueException(Throwable cause) {
super(cause);
}
public UniqueException(String message) {
super(message);
}
public UniqueException(String message, Throwable cause) {
super(message, cause);
}
}
實現ExceptionMapper
/**
* 資料表約束異常處理器.
*
* @author lind
* @date 2024/6/4 10:45
* @since 1.0.0
*/
@Provider
public class DbViolationExceptionMapper implements ExceptionMapper<UniqueException> {
@Override
public Response toResponse(UniqueException exception) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(MapUtil.builder().put("error", exception.getMessage()).build()).type(MediaType.APPLICATION_JSON)
.encoding("utf-8").build();// 非200的請求,這個type無效,一直是text/plain
/*
* return Response.status(Response.Status.OK)
* .entity(MapUtil.builder().put("error", exception.getMessage()).build())
* .type("application/json; charset=UTF-8").build();//
* 200的請求,是可以使用application/json的
*
*/
}
}
註冊ExceptionMapper
在檔案resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
新增內容
com.xx.exception.handler.DbViolationExceptionMapper
業務程式碼直接丟擲異常
if (getCurrentUserId() == null || !getCurrentUserId().equals(userId)) {
throw new UniqueException("許可權不足");
}
相關問題
- 當在ExceptionMapper中返回的Response物件,狀態碼為200時,可以響應為application/json
- 當Response物件狀態碼非200時,響應一直是text/plain
經過除錯與排查,發現當非200時,在這個過濾器org.apache.dubbo.rpc.protocol.rest.filter.ServiceInvokeRestFilter
裡,它出現了兩個content-type,text/plain
不知道是什麼時間被加進去的,如圖
方法執行到這裡時,為響應頭新增了text/plain,事實上,在操作org.apache.dubbo.rpc.protocol.rest.netty.NettyHttpResponse
物件的setStatus()
方法時,它完成了預設content-type的強編碼
NettyHttpResponse的setStatus()方法如下,完成了強編碼
public void setStatus(int status) {
if (status > 200) {
this.addOutputHeaders(RestHeaderEnum.CONTENT_TYPE.getHeader(), MediaType.TEXT_PLAIN.value);
}
this.status = status;
}
這也是業務程式碼中,直接報出自定義異常,在ExceptionMapper捕獲返回json沒有生效的原因,這塊感覺dubbo設計的不太好。