for3st for3st - 2 months ago 8
reST (reStructuredText) Question

Prevent Tomcat from interfering with Jersey/JAX-RS 2 Response Body on HTTP Error Status 4xx or 5xx

I have the following stack for a REST API


  • Jersey 2/JAX RS 2.0

  • Tomcat 7.0.47

  • Jackson 2



My goal is to have a custom response body when an error occurs. I want to be able to send the client an explanation what exactly went wrong for easier debugging.

First I tried to use
@Context HttpServletResponse
and set the http status code there, but it was ignored by jersey (which is the normal behaviour but this is beyond my understanding)

Then I tryed to use
WebApplicationException
like this:

@GET
@Path("/myapi")
public BaseResponse getSomething() {
BaseResponse b = new BaseResponse();
if(error) {
b.setStatusDescription("reason for error");
throw new WebApplicationException(Response.status(Response.Status.CONFLICT).entity(b).build());
}
//add content to BaseReponse
return b
}


But Tomcat returns me somthing like this:

<html>
<head>
<title>Apache Tomcat/7.0.47 - Error report</title>
<style>
<!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22p


Which is the standard Tomcat html output capped by the contet-length of response body I wanted to return (
.entity(b)
- the length of
b
). So it is recognized but Tomcat just overwrites it with its own error page.

As a side note I also tried to just return the Response with the same outcome:

return Response.status(Response.Status.CONFLICT).entity(b).build()


So how do I tell Tomcat to leave me alone and let my own responses through?

Answer

The problem was that I was using the GzipServlet from ehcache which seems to not work porperly with jersey. During the multiple phases the response wrapper threw exceptions.

This is the dependency of ehcache:

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-web</artifactId>
            <version>2.0.4</version>
        </dependency>

And the problematic servlet definition in web.xml

<filter>
        <filter-name>GzipFilter</filter-name>
        <filter-class>net.sf.ehcache.constructs.web.filter.GzipFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>/rest/*</url-pattern>
    </filter-mapping>

As an alternative Im using Jetty Servlet now: http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/servlets/GzipFilter.html

<dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlets</artifactId>
            <version>8.1.0.RC5</version>
        </dependency>

web.xml

<filter>
  <filter-name>GzipFilter</filter-name>
  <filter-class>org.eclipse.jetty.servlets.GzipFilter</filter-class>
  <init-param>
    <param-name>mimeTypes</param-name>
    <param-value>text/html,text/plain,text/xml,application/xhtml+xml,text/css,application/javascript,image/svg+xml</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>GzipFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

As disclaimer: yes I know I can activate gzip in tomcat config, but Im writing a testserver that must be able to have endpoints with and without gzip.