Error Handling

Error handling is accomplished through the use of default response listeners. These are listeners that can generate a response if the exchange is ended without a response being sent.

This is completely different to Servlet error handling. Servlet error handling is implemented as part of Undertow Servlet, and follows the standard Servlet rules.

In general there are two types of errors that we need to worry about, handlers that throw exceptions or handlers that set an error response code and then call HttpServerExchange.endExchange().

Exceptions

The easiest way to handle exceptions is to catch them in an outer handler. For example:

public class ErrorHandler implements HttpHandler {

    @Override
    public void handleRequest(final HttpServerExchange exchange) throws Exception {
        try {
            next.handleRequest(exchange);
        } catch (Exception e) {
            if(exchange.isResponseChannelAvailable()) {
                //handle error
            }
        }
    }
}

The allows your application to handle exceptions in whatever manner you see fit.

If the exception propagates out of the handler chain a 500 response code will be set and the exchange can be ended.

Default Response Listeners

Default response listener allow you to generate a default page if the exchange is ended without a response body. These handlers should test for an error response code, and then generate an appropriate error page.

Note that these handlers will be run for all requests that terminate with no content, but generating default content for successful requests will likely cause problems.

Default response listeners can be registered via the HttpServerExchange#addDefaultResponseListener(DefaultResponseListener) method. They will be called in the reverse order that they are registered, so the last handler registered is the first to be called.

The following example shows a handler that will generate a simple next based error page for 500 errors:

public class SimpleErrorPageHandler implements HttpHandler {

    private final HttpHandler next;

    public SimpleErrorPageHandler(final HttpHandler next) {
        this.next = next;
    }

    @Override
    public void handleRequest(final HttpServerExchange exchange) throws Exception {
        exchange.addDefaultResponseListener(new DefaultResponseListener() {
            @Override
            public boolean handleDefaultResponse(final HttpServerExchange exchange) {
                if (!exchange.isResponseChannelAvailable()) {
                    return false;
                }
                Set<Integer> codes = responseCodes;
                if (exchange.getResponseCode() == 500) {
                    final String errorPage = "<html><head><title>Error</title></head><body>Internal Error</body></html>";
                    exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, "" + errorPage.length());
                    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html");
                    Sender sender = exchange.getResponseSender();
                    sender.send(errorPage);
                    return true;
                }
                return false;
            }
        });
        next.handleRequest(exchange);
    }
}