簡體   English   中英

如何覆蓋 Dropwizard 的默認資源異常處理?

[英]How can I override Dropwizard's default resource exception handling?

假設我在 Dropwizard 中有一個端點,比如說

@GET
public Response foo() { throw new NullPointerException(); }

當我點擊這個端點時,它會記錄異常和所有內容,這很棒! 我喜歡它。 我不太喜歡的是它向用戶返回一個大的狀態對象, status: ERROR (很好)以及一個巨大的堆棧跟蹤,我不太興奮。

顯然,最好是我自己捕捉和處理異常,但有時它們會漏掉。 每次都圍繞整個資源編寫一個 try catch 塊很好,但是 (a) 它很麻煩,並且 (b) 我總是更喜歡自動化的解決方案而不是“你必須記住”的解決方案。

所以我想要的是執行以下操作的東西:

  1. 記錄堆棧跟蹤(我使用 slf4j,但我認為它適用於任何情況)
  2. 返回一個通用錯誤響應,它不會公開有關我的服務器的潛在特權信息!

我覺得必須有一種內置的方法來做到這一點——它已經以一種相對好的方式處理異常——但是搜索文檔沒有發現任何東西。 對此有什么好的解決方案嗎?

正如評論中的惡臭所暗示的那樣,答案是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM