Jetty is helping my application too much. Whenever some unhandled Exception leaks out the top, Jetty takes it upon itself to build a very verbose response and spam it onto my clients
HTTP/1.1 500 com.mongodb.MongoException: No replica set members available in [ { address:'localhost/127.0.0.1:27017', ok:true, ping:0.49878865, isMaster:false, isSecondary:true, setName:dmReplSet, maxBsonObjectSize:16777216, },{ address:'localhost/127.0.0.1:27018', ok:true, ping:0.2565605, isMaster:false, isSecondary:true, setName:dmReplSet, maxBsonObjectSize:16777216, } ] for { "mode" : "primary"}
along with 14K of stacktrace wrapped in a very nice HTML page. The problem is, I don't want the details of the issue leaking out to the clients and, further, this is a JSON Web App accepting and emitting application/json content NOT the HTML Jetty has decided my clients want. I would like to suppress this default error handling having Jetty emit just that standard HTTP 500 response
HTTP/1.1 500 Internal Server Error
and no body at all. How do I get this done? It seems like I should be able to just tell Jetty to "no error page" in etc/jetty.xml or etc/jetty-webdefault.xml or something.
So this seems most easily solved without binding myself to Jetty too much by <error-page> in web.xml
<servlet> <servlet-name>ErrorHandler</servlet-name> <servlet-class>device.webapp.ErrorHandler</servlet-class> </servlet> <servlet-mapping> <servlet-name>ErrorHandler</servlet-name> <url-pattern>/ErrorHandler</url-pattern> </servlet-mapping> <error-page> <exception-type>java.lang.Throwable</exception-type > <location>/ErrorHandler</location> </error-page>
Implementing ErrorHandler like
package device.webapp; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.commons.httpclient.*; import org.slf4j.*; /** * The ErrorHandler is intended to catch all unhandled Throwables (as configured in the web.xml) * before they get out to Jetty's verbose ErrorHandler. * */ public class ErrorHandler extends HttpServlet { private static final long serialVersionUID = 1L; private Logger log = LoggerFactory.getLogger( ErrorHandler.class ); @Override protected void service( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { // Analyze the servlet exception Throwable throwable = (Throwable) req.getAttribute( "javax.servlet.error.exception" ); String message = String.format( "Responding 500 - Server Error on URI %s", req.getAttribute( "javax.servlet.error.request_uri" ) ); if ( throwable != null ) { log.error( message, throwable ); } else { log.warn( "Throwable should not be null!" ); log.error( message ); } /* * Interestingly enough, you can't resp.sendError( 500, "Server Error" ) without triggering * Jetty's DefaultErrorHandler which is the core of the problem we are trying to solve! */ resp.setStatus( HttpStatus.SC_INTERNAL_SERVER_ERROR ); } }
It isn't pretty, but it works.