WebSocket i Rest na jednym serwerze Jetty

0

Jest w ogóle możliwe aby na jednym serwerze Jetty postawić websocket i jakieś restowe aplikacje?
Gdy dodam tylko kontekst samego websocketa to działa ale mam problem po dodaniu 2 kontekstów rest działa natomiast przy połączeniu do websocket dostaje komunikat:

onWebSocketError22: org.eclipse.jetty.websocket.api.UpgradeException: Didn't switch protocols

Główna aplikacja:

public class ServerProcess extends WebSocketHandler {

	public static void main(String[] args) throws IOException, ClassNotFoundException {		
		int serverPort = ServerConfiguration.getConfiguration().getServerPort();
		SslContextFactory sslContextFactory = new SslContextFactory();
		sslContextFactory.setKeyStorePath("src/main/resources/keystore.jks");
		sslContextFactory.setKeyStorePassword("159357258456");
		SslConnectionFactory sslConne = new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.toString());
		
		HttpConfiguration http_config = new HttpConfiguration();
		http_config.setSecureScheme("https");
		http_config.setSecurePort(serverPort);
		http_config.setOutputBufferSize(Integer.MAX_VALUE);
		http_config.setRequestHeaderSize(8192);
		http_config.setResponseHeaderSize(8192);
		
		HttpConfiguration https_config = new HttpConfiguration(http_config);
		https_config.addCustomizer(new SecureRequestCustomizer());
		
		HttpConnectionFactory cf = new HttpConnectionFactory(https_config);
				
        //rest
        ServletContextHandler servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
        servletContext.setContextPath("/");
        ServletHolder jerseyServlet = servletContext.addServlet(
                org.glassfish.jersey.servlet.ServletContainer.class, "/*");
        jerseyServlet.setInitOrder(0);
        jerseyServlet.setInitParameter("jersey.config.server.provider.classnames",
                   RestTest.class.getCanonicalName());

        ContextHandlerCollection contextHandlers = new ContextHandlerCollection();
        contextHandlers.setHandlers(new Handler[]
        {servletContext, new ServerProcess()});
		
		Server server = new Server();
		ServerConnector connector = new ServerConnector(server, sslConne, cf);
		connector.setPort(serverPort);
		server.addConnector(connector);
		server.setHandler(contextHandlers);

		try {
			server.start();
			server.dump(System.err);
			server.join();
		} catch (Exception e) {
		}
	}

	@Override
	public void configure(WebSocketServletFactory factory) {
		factory.register(SocketService.class);
	}

}

REST:

@Path("/entry-point")
public class RestTest {

    @GET
    @Path("test")
    @Produces(MediaType.TEXT_PLAIN)
    public String test() {
        return "Test";
    }
}
0

Druga sprawa która mnie nurtuje czy jest jakiś sposób na uruchomienie na serwerze Jetty dla Restów "Token authentication" ?

1

ContextHandlerCollection sam w sobie jest kompozytowym handlerem który wybiera handler faktycznie obsługujący request na podstawie context path. Jak spojrzymy na implementację ContextHandlerCollection to metoda setHandlers analizuje podane jej handlery i wylicza sobie mapę na podstawie której odbywa się delegowanie. Z każdego handlera tworzony jest obiekt Branch:

        Branch(Handler handler)
        {
            _handler=handler;

            if (handler instanceof ContextHandler)
            {
                _contexts = new ContextHandler[]{(ContextHandler)handler};
            }
            else if (handler instanceof HandlerContainer)
            {
                Handler[] contexts=((HandlerContainer)handler).getChildHandlersByClass(ContextHandler.class);
                _contexts = new ContextHandler[contexts.length];
                System.arraycopy(contexts, 0, _contexts, 0, contexts.length);
            }
            else
                _contexts = new ContextHandler[0];
        }

Jak widać działa to fajnie o ile podajemy do setHandlers coś co jest instancją ContextHandler. WebSocketHandler nie jest ContextHandler więc jest po prostu ignorowany i wszystko leci do servlet handlera. Rozwiązanie to obudować WebSocketHandler w ContextHandler:

ContextHandler websocketContextHandler = new ContextHandler("/ws");
websocketContextHandler.setHandler(new ServerProcess());
ContextHandlerCollection contextHandlers = new ContextHandlerCollection();
contextHandlers.setHandlers(new Handler[]{servletContext, websocketContextHandler});

ContextHandlerCollection przy delegacji będzie teraz uzględniał oba handlery, ale uzna że servletowy pasuje bardziej (w dokładną logikę matchującą już się nie zagłębiałem) i oddeleguje do niego. Aby pozbyć się i tego problemu najlepiej kontekst servletowy wrzucić do osobnego brancha:

servletContext.setContextPath("/rest");

Teraz https://.../rest/entry-point/test i wss://.../ws powinny działać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1