java 如何在不向用户显示堆栈跟踪的情况下处理 servlet 过滤器中的错误状态?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14782184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 17:23:09  来源:igfitidea点击:

How do I handle error states in servlet filters without showing the user a stack trace?

javajettyservlet-filtersresteasy

提问by Nathan Friedly

I'm working on a Jetty/RESTEasy app. If I throw a WebApplicationException(myResponse)from one of my REST endpoints, it sends the given response to the client.

我正在开发一个 Jetty/RESTEasy 应用程序。如果我WebApplicationException(myResponse)从我的 REST 端点之一抛出 a ,它会将给定的响应发送到客户端。

When a filter detects an error, I want the same behavior:

当过滤器检测到错误时,我想要相同的行为:

  1. It should stop execution from proceeding, and
  2. It should give the user a clear, JSON-formatted error that does not include a stack trace.
  1. 它应该停止继续执行,并且
  2. 它应该给用户一个清晰的、JSON 格式的错误,不包括堆栈跟踪。

Obviously, just writing to the response stream and returning works from within the doFiltermethod. But this doesn't work for other methods called by doFilter.

显然,只需写入响应流并returndoFilter方法内工作即可。但这不适用于由 调用的其他方法doFilter

Throwing any exception will meet condition #1 but I haven't figured out a sane way to meet condition #2 then. (You can see my best attempt at the bottom.)

抛出任何异常都将满足条件 #1,但我还没有想出一种理智的方法来满足条件 #2。(你可以在底部看到我最好的尝试。)

As Perception explained in his answer, WebApplicationExceptions are treated like any other exception in the context of a Filter, and therefore give the user a nice ugly stack trace.

正如 Perception 在他的回答中所解释的那样,WebApplicationExceptions 在 Filter 的上下文中被视为任何其他异常,因此为用户提供了一个漂亮的丑陋堆栈跟踪。

So, to sum up my questions:

所以,总结一下我的问题:

  • Do serveltt containers have any equivalent to throw new WebApplicationException(Response)?
  • And perhaps more importantly, how do other java projects handle this?
  • serveltt 容器有什么等价物throw new WebApplicationException(Response)吗?
  • 也许更重要的是,其他 java 项目如何处理这个问题?

I have this code in one filter and it works, but I'd prefer a more elegant solution that automatically applies to all filters:

我在一个过滤器中有此代码并且它可以工作,但我更喜欢一个更优雅的解决方案,它可以自动应用于所有过滤器:

public void doFilter(final ServletRequest   request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
    try {
        doFilterOrThrow(request, response, chain);
    } catch (WebApplicationException e) {
        Response res = e.getResponse();
        ((HttpServletResponse) response).sendError(res.getStatus(), (String) res.getEntity());
    }
}

回答by Perception

The specific handling you mention for web application exceptions is only defined within the context of a JAX-RS container, which, by the way, is notthe same thing as a Servlet container.

处理你提到的Web应用程序异常的具体仅一个JAX-RS的容器,其中,顺便说一句,是的范围内定义一样的东西作为一个Servlet容器。

Web filters are handled by the Servlet container, which does not know or care that a JAX-RS container exists within the same application server. It also does not know or care about web application exceptions. So when you throw the WAE from within the filter it is treated just the same as any other exception (server error with a stack trace, or a preconfigured error page if you set one up in your web application).

Web 过滤器由 Servlet 容器处理,它不知道或不关心 JAX-RS 容器是否存在于同一应用服务器中。它也不知道或不关心 Web 应用程序异常。因此,当您从过滤器中抛出 WAE 时,它被视为与任何其他异常一样(服务器错误与堆栈跟踪,或者如果您在 Web 应用程序中设置了一个预配置的错误页面)。

It would seem to me if you are indicating an error to the client you could simply do so from the filter, by writing directly to the response stream. But if you are trying to leverage some existing JAX-RS logic then a (RESTEasy specific) solution would be to flag the request as error'ed out in your filter, then generate a WAE in JAX-RS, using a provider class. Example:

在我看来,如果您向客户端指示错误,您可以通过直接写入响应流来简单地从过滤器中执行此操作。但是,如果您试图利用一些现有的 JAX-RS 逻辑,那么(RESTEasy 特定的)解决方案是在过滤器中将请求标记为错误,然后使用提供程序类在 JAX-RS 中生成 WAE。例子:

@WebFilter(urlPatterns = "*")
public class ForwardingFilter implements Filter {

    @Override
    public void destroy() {
        return;
    }

    @Override
    public void doFilter(final ServletRequest request,
            final ServletResponse response, final FilterChain chain)
            throws IOException, ServletException {
        // Add an error response to be processed by the JAX-RS container.
        // This would obviously be based on some condition.
        request.setAttribute("errorResponse",
                Response.status(500).entity("Didn't work out!").build());
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        return;
    }
}

@Provider
@ServerInterceptor
@HeaderDecoratorPrecedence
@RequestScoped
public class ForwardingHandlerProvider implements PreProcessInterceptor {

    @Override
    public ServerResponse preProcess(final HttpRequest request,
            final ResourceMethod method) throws Failure,
            WebApplicationException {
        final Response errorResponse = (Response) request
                .getAttribute("errorResponse");
        if (errorResponse != null)
            throw new WebApplicationException(errorResponse);
        return null;
    }
}

Since the provider exists in JAX-RS land, the web application exception is processed according to the rules of Section 3.3.4 of the JAX-RS specification, and you get the desired response at the client side.

由于提供者存在于 JAX-RS 领域,因此根据 JAX-RS 规范第 3.3.4 节的规则处理 Web 应用程序异常,并在客户端获得所需的响应。

* EDIT:*

* 编辑:*

The bottom line is, there is no standard Java EE prescribed way (currently) to handle servlet exceptions in a centralized fashion similar to what is available in JAX-RS. Since you are using JBoss/RestEASY though, you could utilize the JBoss Seam Catchlibrary to get pretty close.

最重要的是,没有标准的 Java EE 规定的方法(当前)以类似于 JAX-RS 中可用的集中方式处理 servlet 异常。由于您使用的是 JBoss/RestEASY,因此您可以利用 JBoss Seam Catch库来获得非常接近的结果。

@HandlesExceptions
public class ExceptionHandler {
    public void handleServletException(
            final @Handles @WebRequest CaughtException<ServletException> caught,
            @Context final HttpServletResponse response) {
        try {
            response.sendError(500, "An error occured");
        } catch (final IOException ioe) {
            System.err.println("Dumb IO Exception: " + ioe);
        }
    }
}

The above illustrates an exception handler, as described in the Seam Catch documentation. Note that the library is in massive flux right now, so you will want to utilize it only as a last resort.

上面说明了一个异常处理程序,如Seam Catch 文档中所述。请注意,该库现在处于巨大的变化之中,因此您只能将其用作最后的手段。