简体   繁体   中英

Supporting Angular 2's PathLocationHandler with Jetty (using a 404 error page)

I'm trying to work out how to support Angular 2's PathLocationHandler with an embedded Jetty server. To do that, as I understand it, I need to redirect any 404 request to the top-level index.html file ( https://stackoverflow.com/a/34104534/797 )

I figured the way to do that was to give the ContextHandler and ErrorHandler which redirected all 404 requests back to /index.html with something like the code below (I'm actually doing it in a context xml file, but the code might be easier to conceptualize/debug).

What I see is that my error handler is completely ignored, and I'm not sure how to fix that or, alternately, how I ought be configuring things instead.


import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;

public class JettyTest {

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);

        ResourceHandler resourceHandler = new ResourceHandler();
        resourceHandler.setResourceBase("/tmp/directory-with-just-an-index.html-file");

        ContextHandler contextHandler = new ContextHandler("/context-path");

        ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
        errorHandler.addErrorPage(404, "/index.html");

        contextHandler.setHandler(resourceHandler);
        contextHandler.setErrorHandler(errorHandler);

        server.setHandler(contextHandler);

        server.start();
        System.out.println("Started!");
        server.join();
    }

}

Stepping through the Jetty code for a request like http://localhost:8080/context-path/some-file-which-is-not-present.html , what I see is that the ResourceHandler finds no matching files in it's resourceBase, and then calls...

    //no resource - try other handlers
    super.handle(target, baseRequest, request, response);
    return;

...then we bubble up out of the ContextHandler and eventually HttpChannelOverHttp sends out a 404 because the request isn't considered to have been handled.

    if (!_response.isCommitted() && !_request.isHandled())
        _response.sendError(404);

Perhaps Jetty is expecting ResourceHandler to signal the 404 error in some different way? Or more likely, I'm failing to account for something in the way I'm configuring things.

The misconfiguration hint may be that https://www.eclipse.org/jetty/documentation/9.3.x/resource-handler.html mentions for ResourceHandler "Requests for resources that do not exist are let pass (Eg no 404's).", but that leaves me unclear on where to go next other than 'write your own handler' which I'd prefer to avoid.

Any pointers much appreciated!

Some amount of banging my head against things brought me to the following, which does do what I want, though I'd still certainly accept an answer which explained why ResourceHandler isn't appropriate for what I want...

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

public class JettyTest {

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);

        ServletContextHandler servletContextHandler = new ServletContextHandler();
        servletContextHandler.setContextPath("/context-path");
        servletContextHandler.setResourceBase("/tmp/directory-with-just-an-index.html-file");
        servletContextHandler.addServlet(new ServletHolder(new DefaultServlet()), "/*");

        ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
        errorHandler.addErrorPage(404, "/index.html");

        servletContextHandler.setErrorHandler(errorHandler);

        server.setHandler(servletContextHandler);

        server.start();
        System.out.println("Started!");
        server.join();
    }

}

...Now to try to turn that back into an xml context file :)


...which I eventually did with the following in case anyone needs it later.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">

<Configure class="org.eclipse.jetty.servlet.ServletContextHandler" id="myContext">

    <Set name="contextPath">/context-path</Set>
    <Set name="resourceBase">/tmp/directory-with-just-an-index.html-file</Set>

    <!-- Direct all 404s to index.html (required by Angular's PathLocationStrategy) -->
    <Set name="errorHandler">
        <New class="org.eclipse.jetty.servlet.ErrorPageErrorHandler">
            <Call name="addErrorPage">
                <Arg type="int">404</Arg>
                <Arg type="String">/index.html</Arg>
            </Call>
        </New>
    </Set>

    <Call name="addServlet">
        <Arg><New class="org.eclipse.jetty.servlet.ServletHolder">
            <Arg>
                <New class="org.eclipse.jetty.servlet.DefaultServlet"></New>
            </Arg>
        </New></Arg>
        <Arg>/*</Arg>
    </Call>

</Configure>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM