Jetty 和 Dropwizard:如何始终返回 200 而不是 404、500 等

Posted

技术标签:

【中文标题】Jetty 和 Dropwizard:如何始终返回 200 而不是 404、500 等【英文标题】:Jetty and Dropwizard: how to return always 200 instead of 404, 500, etc 【发布时间】:2015-07-25 02:47:21 【问题描述】:

我正在使用 Jetty-Jersey-Jackson 堆栈附带的 Dropwizard 0.8.0。 出于安全原因,我想添加一个过滤器,使通过 Jersey 定义的特定路由的每个请求始终返回 200,即使出现错误(4xx、5xx 等)也是如此。

这可以通过 Jetty/Servlet 过滤器实现吗?我可以在请求通过 Jersey 资源(控制器)但在返回给客户端之前拦截请求,以修改 http 状态码吗?

更新:

我正在尝试使用 ServletFilter 执行此操作,但似乎在执行我的代码之前将响应发送到客户端。 我是这样写过滤器的:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException

    if (response instanceof HttpServletResponse) 
        /* No pre-processing */

        chain.doFilter(request, response);

        /* Post-processing: */

        HttpServletResponse modifiedResponse = (HttpServletResponse) response;

        if (modifiedResponse.getStatus() != 200) 
            modifiedResponse.setStatus(200);
        
    

有了这个,在 Dropwizard 中注册:

environment.servlets().addFilter("MyCustomFilter", new MyCustomFilter())
           .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/mypath/*");

过滤器被执行,在 access.log 中我看到所有状态码为 200 的请求;但客户端总是得到“真正的”状态码(例如,404 或“不允许的方法”)。 似乎在执行过滤器的最后一部分之前将响应发送到客户端。此外,我无法修改响应正文。我也尝试使用 HttpServletResponseWrapper,但没有运气。

【问题讨论】:

【参考方案1】:

您可以创建您的自定义javax.ws.rs.ext.ExceptionMapper<RuntimeException>。在这种情况下,您从服务器获得的每个异常都可以解析为 200。

检查此guy。它应该很容易与您需要的东西集成。

而不是教程向您展示的内容,例如以下示例:

 if (webAppException.getResponse().getStatus() == 401) 
      return Response
        .status(Response.Status.UNAUTHORIZED)
        .entity(new PublicFreemarkerView("error/401.ftl"))
        .build();
 

你的代码将是

 if (webAppException.getResponse().getStatus() == 401) 
      return Response
        .status(Response.Status.OK)
        .build();
 

【讨论】:

请注意,有些错误不能以这种方式处理(例如:400 Bad Request)。这是因为有一类错误没有上下文和/或没有请求,所以它们不能被发送到用户代码中进行处理和响应。 这是个好主意,但是使用 ExceptionMapper 我也无法捕获 2xx 响应(例如:204)。我已经用 servlet 过滤器更新了我的答案。不幸的是它不起作用..【参考方案2】:

我正在使用最终有效的解决方案更新问题:我使用 Jersey 过滤器而不是 Jetty http 过滤器,以便直接管理来自 Jersey 的 Response 对象。

显然,这仅在您使用 Jetty+Jersey 时才有效,而不是与 Jetty 单机版一起使用。

这是我正在使用的过滤器:

/**
 * When active, this filter transforms all responses for specified basePath to 200, even in case of error.
 */
@Provider
public class DiscardErrors implements ContainerResponseFilter

    private String basePath;

    public DiscardErrors(String basePath)
    
        this.basePath = basePath;
    

    @Override
    public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException
    
        if containerRequestContext.getUriInfo().getPath().startsWith(this.basePath) 
            if (containerResponseContext.getStatus() != 200)  // Check if response code is different from 200
                containerResponseContext.setStatus(200); // Force 200 status code
                containerResponseContext.setEntity(""); // Empty body
            
        
    


并在 Dropwizard 中注册:

environment.jersey().register(new DiscardErrors("/"));

【讨论】:

以上是关于Jetty 和 Dropwizard:如何始终返回 200 而不是 404、500 等的主要内容,如果未能解决你的问题,请参考以下文章

如何从单元测试运行 dropwizard 服务器

如何告诉 Spring Boot 忽略 Jetty 并始终使用 Tomcat?

如何基于 Kafka 构建一个关系型数据库

Dropwizard休眠字段未填充

我如何禁用选项请求方法甚至在 dropwizard 中处理

如何通过 dropwizard-flyway 库使用授权版本的 flyway