Embedded Jetty handling urls to serve content

2019-03-04 11:59发布

I am using embedded Jetty with Guice and am wondering the best way to handle serving my single page application.

I wish for Jetty to handle requests like so (in priority order):

  • /socket must be handled by the websocket servlet

  • /fs/read/*, anything that matches this url I need to be handled by a custom servlet

  • /*, anything that matches this url should be served from the /web on the classpath of my Java application assuming it isn't handled by the above. If the resource does not exist, then it serves /web/index.html

Now I am wondering the best way to handle this? It seems heavy handed to use a REST framework as I don't really have any rest services.

Here is currently how I am setting up Jetty:

ServletHolder servletHolder = new ServletHolder(DefaultServlet.class);

ServletContextHandler servletContextHandler = new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);
servletContextHandler.addFilter(GuiceFilter.class, "/*", EnumSet.allOf(DispatcherType.class));
servletContextHandler.addServlet(servletHolder, "/");

ResourceHandler resHandler = new ResourceHandler();
resHandler.setBaseResource(Resource.newClassPathResource("/web"));
server.setHandler(resHandler);

Here is my Guice ServletModule:

serve("/socket/*").with(WebSocketManagerServlet.class);
serve("/fs/read/*").with(MyCustomServlet.class);

However, I am not sure how to do the last rule where it redirects anything not matched to index.html and still have jetty send out the right headers which the correct mime types for css/js/html, etc. Jetty also probably does some memory mapping and fancy things to serve these quickly which I'd like to maintain.

1条回答
乱世女痞
2楼-- · 2019-03-04 12:35

General Note: ResourceHandler is not for use with an application that has a ServletContext.
The ResourceHandler is ultra-primitive (and very naive) and intended only to support web applications that use raw Jetty handlers only.
Do not mix ResourceHandler with ContextHandler, ServletContextHandler, or WebAppContext.

Based on what you have asked, I think you want this ...

URL urlToWebDir = findUrlTo("/web");
ServletContextHandler servletContextHandler = 
    new ServletContextHandler(server, "/", ServletContextHandler.SESSIONS);
servletContextHandler.setContextPath("/");
servletContextHandler.setWelcomeFiles(new String[] { "index.html" });
servletContextHandler.setBaseResource(Resource.newResource(urlToWebDir));
servletContextHandler.addServlet(DefaultServlet.class, "/");

ErrorPageErrorHandler errorMapper = new ErrorPageErrorHandler();
errorMapper.addErrorPage(404,"/"); // map all 404's to root (aka /index.html)
servletContextHandler.setErrorHandler(errorMapper);

This is a simpler setup for your "/web" path requirement.

The BaseResource is the URL (it can be a jar:file:// or file:// URL reference) which is used by the DefaultServlet to serve your static content.

So that if a request comes in on /image.png then {baseResource}/image.png is served (and a request on /icons/avatar.gif is served from {baseResource}/icons/avatar.gif

The WelcomeFiles sets up the index.html resolving, so that a request on / results in serving file {baseResource}/index.html. (also works if request is /alternate/path/deep/in/your/tree/ then /alternate/path/deep/in/your/tree/index.html is served (if it exists).

Bonus note: DefaultServlet supports pre-compressed static content serving. Meaning if you gzip your content and keep a copy of it along-side, then the compressed version is served to your users if their browser says it supports compressed responses. (example: request for /js/hugelib.js with old browser that doesn't support compressed responses, then {baseResource}/js/hugelib.js is served. But if browser supports compressed responses, then {baseResource}/js/hugelib.js.gz is served instead)

查看更多
登录 后发表回答