Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

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.

Obviously, just writing to the response stream and returning works from within the doFilter method. But this doesn't work for other methods called by 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.)

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.

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?

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());
    }
}
like image 532
Nathan Friedly Avatar asked Feb 08 '13 22:02

Nathan Friedly


People also ask

How do you handle exceptions thrown by another servlet in an application?

Each error-page element should have either error-code or exception-type element. We define the exception handler servlet in location element. Based on above configuration, if the application throw 404 error or ServletException, it will be handled by AppExceptionHandler servlet.

Which of the following request attributes that an error handling servlet can access to Analyse the nature of error exception?

Q 25 - Which of the following request attributes that an error-handling servlet can access to analyse the nature of error/exception? A - javax.

What is the correct syntax to configure filters in servlets?

Specifying Filter Configuration To map a filter to a servlet you: Declare the filter using the <filter> element in the web application deployment descriptor. This element creates a name for the filter and declares the filter's implementation class and initialization parameters.


1 Answers

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 not the same thing as a Servlet container.

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).

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:

@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.

* 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 Catch library to get pretty close.

@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.

like image 167
Perception Avatar answered Oct 20 '22 20:10

Perception