2016-12-16 59 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“捕获”,因此进程没有关闭。对此有何想法? –