如何配置DropWizard来解释请求失败?

时间:2015-05-04 13:38:17

标签: java dropwizard

如果我在没有请求正文的情况下发送JSON:

POST /stuff
Content-Type: application/json
Content-Length: 0
                       <---- Body missing!

...到我的DropWizard(泽西岛)资源,

private class PostBody { public String a };

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response create(@Valid PostBody body)
{ … }

现在,我只在日志中找到一行:

127.0.0.1 - - [04/May/2015:13:21:25 +0000] "POST /stuff HTTP/1.1" 422 370 232 232

HTTP 422不是一个不合理的提示,但我必须相信这里有更详细的信息。同样,如果标题丢失或路径组件与提供的格式不匹配,我希望看到一条日志行,如#34; Header ____无法解析&#34;。

127.0.0.1 - - [04/May/2015:13:21:25 +0000] Received "POST /stuff HTTP/1.1"
127.0.0.1 - - [04/May/2015:13:21:25 +0000] Error: Body could not be parsed (Failure while deserializing field "a")
127.0.0.1 - - [04/May/2015:13:21:25 +0000] "POST /stuff HTTP/1.1" 422 370 232 232

DropWizard中是否内置了此类日志记录?我该如何启用它?

2 个答案:

答案 0 :(得分:1)

在这种情况下,您需要覆盖异常映射器。在422的情况下,您需要为ConstraintViolationException实现异常映射器。

请参阅此答案:Override DropWizard ConstraintViolation message

答案 1 :(得分:0)

默认情况下,Dropwizard / Jersey将异常映射到响应(默认异常映射器),在某些情况下,日志记录是有限的,因此不是很有用;因为简单或只是强迫开发人员自己做更好的记录。供参考,更完整的描述:

  

泽西岛,或者我应该说JAX-RS,公开了一种机制,允许您将抛出的Exception或Throwable映射到REST响应,而不是未处理并作为某些堆栈跟踪呈现给用户或错误文本。(这个机制要求你实现通用的ExceptionMapper接口,然后注册它。)这对于那些喜欢在使用API​​时将错误返回给客户端的REST API来说非常好,比如返回异常的JSON表示可以在客户端上解析和处理。“(source

以编程方式,可以通过以下步骤创建自己的自定义异常映射器。代码正在考虑Dropwizard 0.9.x,以及你问题中的具体情况;但是,为了解决其他案例/例外,这个过程是类似的。为简单起见,也省略了一些行:

  1. 禁用默认的异常映射器:

    • 通过您的Application子类:

      AbstractServerFactory sf = (AbstractServerFactory) config.getServerFactory();
      sf.setRegisterDefaultExceptionMappers( false );
      
    • 通过您的应用程序配置:

      server:
          registerDefaultExceptionMappers: false
      
  2. 创建自定义异常映射器,通过添加日志记录(JSON和验证异常)来扩展原始异常映射器:

    public class CustomConstraintViolationExceptionMapper extends ConstraintViolationExceptionMapper
    {
        @Override
        public Response toResponse( ConstraintViolationException exception )
        {
            Response superResponse = super.toResponse( exception );
            ValidationErrorMessage validationErrorMessage = (ValidationErrorMessage) superResponse.getEntity();
            log.error( String.format( "%s\t%s",
                                  exception.getMessage(),
                                  String.join( ";", validationErrorMessage.getErrors() ) ) );
    
            return superResponse;
        }
    }
    
    public class CustomJsonProcessingExceptionMapper extends JsonProcessingExceptionMapper
    {
        @Override
        public Response toResponse( JsonProcessingException exception )
        {
             log.error( String.format( "%s", exception.getOriginalMessage() ) );
             return super.toResponse( exception );
        }
    }
    
  3. 注册您创建的自定义异常映射器:

    environment.jersey().register( new CustomConstraintViolationExceptionMapper() );
    environment.jersey().register( new CustomJsonProcessingExceptionMapper() );
    
  4. 不要忘记添加其他默认的异常映射器(如果需要 - check Dropwizard's code):

    environment.jersey().register( new LoggingExceptionMapper<Throwable>(){} );
    environment.jersey().register( new EarlyEofExceptionMapper() );
    
  5. 最终结果将记录为:

    ERROR [2016-07-05 13:06:36,690] x.y.CustomConstraintViolationExceptionMapper: The request entity had the following errors:  field may not be empty
    ERROR [2016-07-05 13:19:41,326] x.y.CustomJsonProcessingExceptionMapper: Unrecognized field "UnknownField" (class x.y.z.Xyz), not marked as ignorable
    
  6. 有关该主题的更多信息,您还可以遵循以下参考: