Search code examples
jettyjava-websocket

Jetty websockets and abstracthandler


I am trying to get a normal AbstractHandler and WebSocketAdapter to work at the same time.

jetty-version: jetty-9.4.8.v20171121,

I have a simple class Foo that extends org.eclipse.jetty.server.handler.AbstractHandler.

Also a class Bar that extends org.eclipse.jetty.websocket.api.WebSocketAdapter

Glue-class:

@SuppressWarnings("serial")
public class Glue extends WebSocketServlet {
  @Override
  public void configure(WebSocketServletFactory factory) {
    factory.register(Bar.class);
  }
}

Now I try to make a server that uses both of these:

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.setHandler(new Foo());
ServletHolder holder = new ServletHolder("ws-events", Glue.class);
context.addServlet(holder, "/whatever/*");

Server server = new Server(80);
server.setHandler(context);
server.start();

This starts and when I go to localhost I see the content that Foo should display, but I can't connect to the websocket. It looks like all requests go to Foo.

When I remove the context.setHandler(new Foo()); line it obviously does not display the html-content anymore, but I can connect to the websocket.

I want both to work at the same time.


Solution

  • Don't mix Handlers for responses and ServletContextHandler.

    Change Foo to be a Servlet, assign it a reasonable url-pattern as a Servlet.

    The reason is because your Foo executes before any of the servlet code.

    The only other way to accomplish this with a Handler is to make your Foo handler websocket and HTTP/1.1 upgrade aware and not execute when the request is detected to be for WebSocket upgrade. (This is a bad idea! don't do it! its not backward compatible when WebSocket over HTTP/2 arrives!)

    Also note, you can have your Glue class implement doGet() and service HTML if a non-websocket client asks for HTTP content on the same url-pattern.

    BTW, If you want static html to be served, don't do that in your own code. Assign a reasonable "Base Resource Location" to your ServletContextHandler and add a DefaultServlet to serve the static resources that don't match another url-pattern.

    See prior answer on this: https://stackoverflow.com/a/20223103/775715