[英]How can I override Dropwizard's default resource exception handling?
假設我在 Dropwizard 中有一個端點,比如說
@GET
public Response foo() { throw new NullPointerException(); }
當我點擊這個端點時,它會記錄異常和所有內容,這很棒! 我喜歡它。 我不太喜歡的是它向用戶返回一個大的狀態對象, status: ERROR
(很好)以及一個巨大的堆棧跟蹤,我不太興奮。
顯然,最好是我自己捕捉和處理異常,但有時它們會漏掉。 每次都圍繞整個資源編寫一個 try catch 塊很好,但是 (a) 它很麻煩,並且 (b) 我總是更喜歡自動化的解決方案而不是“你必須記住”的解決方案。
所以我想要的是執行以下操作的東西:
我覺得必須有一種內置的方法來做到這一點——它已經以一種相對好的方式處理異常——但是搜索文檔沒有發現任何東西。 對此有什么好的解決方案嗎?
正如評論中的惡臭所暗示的那樣,答案是ExceptionMapper
。 你需要一個這樣的類:
@Provider
public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> {
@Override
public Response toResponse(RuntimeException runtime) {
// ...
}
}
您可以在toResponse
方法中執行任何您喜歡的日志記錄或其他操作,並且返回值是實際發送給請求者的值。 這樣你就有了完全的控制權,並且應該設置合理的默認值——記住這是為了漏掉的錯誤,而不是你真正希望看到的錯誤! 這也是根據您獲得的異常類型設置不同行為的好時機。
要真正做到這一點,只需在主 dropwizard 應用程序的run
方法中插入以下行(或類似行):
environment.jersey().register(new RuntimeExceptionMapper());
其中environment
是應用程序run
方法的Environment
參數。 現在,當您在某處遇到未捕獲的RuntimeException
,這將觸發,而不是之前 dropwizard 所做的任何事情。
注意:這仍然不是不小心捕捉和處理異常的借口!
將以下內容添加到您的 yaml 文件中。 請注意,它將刪除 dropwizard 添加的所有默認異常映射器。
server: registerDefaultExceptionMappers: false
編寫一個自定義異常映射器,如下所示:
public class CustomExceptionMapper implements ExceptionMapper<RuntimeException> {
@Override
public Response toResponse(RuntimeException runtime) {
// ...
}
}
然后在 jersey 中注冊異常映射器: environment.jersey().register(new CustomExceptionMapper());
已經在評論中提到了這一點,但后來我想我會用一個用例來嘗試一下。
建議您開始區分您將拋出的Exception
。 對您知道的失敗使用自定義異常,並使用漂亮的日志記錄拋出那些失敗。 同時RuntimeException
實際上應該是固定的。 無論如何,如果您不想向最終用戶顯示堆棧跟蹤,您可能會捕獲通用異常,記錄詳細信息並相應地自定義響應和實體。
你可以定義一個
public class ErrorResponse {
private int code;
private String message;
public ErrorResponse() {
}
public ErrorResponse(int code, String message) {
this.code = code;
this.message = message;
}
... setters and getters
}
然后在您的資源代碼中,您可以將方法修改為 -
@GET
public Response foo() {
try {
...
return Response.status(HttpStatus.SC_OK).entity(response).build();
} catch (CustomBadRequestException ce) {
log.error(ce.printStackTrace());
return Response.status(HttpStatus.SC_BAD_REQUEST).entity(new ErrorResponse(HttpStatus.SC_BAD_REQUEST, ce.getMessage())).build();
} catch (Exception e) {
log.error(e.printStackTrace(e));
return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).entity(new ErrorResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, e.getMessage())).build();
}
}
本文詳細介紹了帶有自定義ExceptionMapper 的Jersey 的Checked 和 Unchecked Exceptions實現:
https://www.codepedia.org/ama/error-handling-in-rest-api-with-jersey/
官方 Dropwizard 文檔還介紹了一種更簡單的方法,只需使用WebApplicationException捕獲即可:
@GET
@Path("/{collection}")
public Saying reduceCols(@PathParam("collection") String collection) {
if (!collectionMap.containsKey(collection)) {
final String msg = String.format("Collection %s does not exist", collection);
throw new WebApplicationException(msg, Status.NOT_FOUND)
}
// ...
}
https://www.dropwizard.io/en/stable/manual/core.html#responses
通過簡單地注冊在主類的 run 方法中創建的自定義異常映射器,它對我有用。
environment.jersey().register(new CustomExceptionMapper());
其中 CustomExceptionMapper 可以像這樣實現 ExceptionMapper 類
public class CustomExceptionMapperimplements ExceptionMapper<Exception>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.