2016-12-16 84 views
3

假設我有在Dropwizard端點,說如何覆蓋Dropwizard的默認資源異常處理?

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

當我打這個端點它記錄異常和一切,這是偉大的!我喜歡它。我最不喜歡的是它向status: ERROR(這很好)的用戶返回一個很大的狀態對象,以及一個巨大的堆棧跟蹤,我不那麼興奮。

很明顯,最好是自己動手處理和處理異常情況,但有時他們會滑過去。每次在整個資源周圍編寫try catch塊都很好,但(a)很麻煩,(b)我總是更喜歡自動化解決方案來「記住」解決方案。

所以我想什麼是什麼,執行以下操作:

  1. 日誌中的堆棧跟蹤(我用SLF4J但我相信它會爲任何工作)
  2. 返回通用錯誤響應,這不會公開有關我的服務器的潛在特權信息!

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

+2

檢查了這一點:http://gary-rowe.com

public class CustomExceptionMapper implements ExceptionMapper<RuntimeException> { @Override public Response toResponse(RuntimeException runtime) { // ... } } 

然後在澤西島註冊的異常映射器/ agilestack/2012/10/23/how-to-implement -a runtimeexceptionmapper-for-dropwizard/ – Reek

+0

建議開始區分你拋出的異常。使用自定義異常來處理你知道的故障,並用漂亮的日誌記錄把它們拋出在相同的運行時異常應該拋出並修復。如果你不想把它顯示給最終用戶,你可能會捕獲一個通用的異常,記錄細節並相應地定製'Response'和'entity'。 – nullpointer

回答

0

已經在評論中提到了這個,但後來我想我會試用一個用例。

建議您開始區分您將投擲的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(); 
    }  
} 
+1

這可能是一個好建議,但它並沒有真正解決這個問題,即在處理未捕獲的異常時如何改變dropwizard的行爲。這個問題的隱含前提,你顯然不同意,是我不想在try-catch塊中包圍每個端點,當dropwizard實質上爲我做這些。 –

1

正如臭氣在評論中提到,答案是ExceptionMapper。你需要這樣一類:

@Provider 
public class RuntimeExceptionMapper implements ExceptionMapper<RuntimeException> { 
    @Override 
    public Response toResponse(RuntimeException runtime) { 
     // ... 
    } 
} 

你可以做任何記錄或等你在toResponse方法等,以及返回值是什麼是實際發送到請求者。通過這種方式,您可以完全控制,並且應該設置理智的默認值 - 請記住,這是針對錯誤,而不是您實際期望看到的錯誤!根據您所得到的例外情況,這也是設置不同行爲的好時機。

要真正使這個做任何事情,只需插入下面的行(或類似)在主dropwizard應用run方法:

environment.jersey().register(new RuntimeExceptionMapper()); 

其中environmentEnvironment參數到應用程序的run方法。現在,當你在某個地方沒有捕獲到一個未捕獲的RuntimeException時,這將觸發,而不是之前的任何dropwizard。

注意:這仍然不是一個理由不仔細捕捉和處理你的例外!

+0

這很有趣,但這不包括配置初始化期間拋出的異常,是嗎?因爲你只能在'run'方法中設置它,對吧?就我個人而言,我希望Dropwizard在配置初始化期間拋出異常,以終止進程 –

1

將以下內容添加到您的yaml文件中。請注意,它將刪除dropwizard添加的所有默認異常映射器。

server: registerDefaultExceptionMappers: false

寫,如下自定義異常映射: environment.jersey().register(new CustomExceptionMapper());

+0

我試過這樣做,但在配置初始化期間拋出的異常仍然被dropwizard「捕獲」,因此進程沒有關閉。對此有何想法? –