不同上下文中的嵌入式 Jetty WebSocket 服务器

问题描述 投票:0回答:1

我正在尝试在不同的上下文中运行具有不同内容的嵌入式 Jetty websocket 服务器。

如果我将 websocket 部分放在 / 上下文中,它就可以工作,但我想在那里服务器其他内容。如果我将 websocket 部分放入任何其他上下文中,它就不起作用。

这是我的代码:

    public WebsocketServer(int port, Model model, SessionManager sessionManager) throws Exception {
        Server server = new Server(port);
        server.setRequestLog((request, response) -> log_.info("request {}", request));

        ContextHandlerCollection handlers = new ContextHandlerCollection();

        ServletContextHandler sch;

        sch = new ServletContextHandler();
        sch.setContextPath("/model");
        sch.addServlet(new ServletHolder(new ModelServlet(model)), "/");
        sch.setResourceBase("cfg");
        handlers.addHandler(sch);

        sch = new ServletContextHandler();
        sch.setContextPath("/web");
        sch.addServlet(DefaultServlet.class, "/*");
        sch.setResourceBase("cfg");
        sch.setWelcomeFiles(new String[]{"websocket.html"});
        handlers.addHandler(sch);

        sch = new ServletContextHandler();
        sch.setContextPath("/");     // <---- would like to change this context to /ws
        Servlet websocketServlet = new JettyWebSocketServlet() {
            @Override
            protected void configure(JettyWebSocketServletFactory factory) {
                factory.addMapping("/", (req, res) -> {
                    Session s = new Session(req);
                    sessionManager.add(s);
                    return s;
                });
            }
        };
        sch.addServlet(new ServletHolder(websocketServlet), "/");
        JettyWebSocketServletContainerInitializer.configure(sch, null);
        handlers.addHandler(sch);

        sch = new ServletContextHandler();
        sch.setContextPath("/*");
        sch.addServlet(DefaultServlet.class, "/*");
        sch.setResourceBase("cfg");
        handlers.addHandler(sch);

        server.setHandler(handlers);

        server.start();
    }

如果我将 JettyWebSocketServlet 放在 / 上下文中,它可以工作,但它永远不会到达我的 DefaultServlet。我尝试将 JettyWebSocketServlet 更改为 /ws,但随后我的网页无法连接,但我确实从 DefaultServlet 获得了结果。无论哪种情况,我的 ModelServlet 都可以在 /model 上下文中工作。

我的网页尝试连接到 ws://localhost:8080/ws

我使用的是jetty 11.0.16

websocket jetty embedded-jetty jetty-11
1个回答
0
投票

Jetty 11 现已停止社区支持

参见:https://github.com/jetty/jetty.project/issues/10485

您的设置中存在一些根本性错误。

您的设置也不会通过将其拆分为不同的 ServletContext 而获得任何好处。

首先,您对

DefaultServlet
的使用,
DefaultServlet
始终被命名为“default”,并位于
/
的“默认”servlet 映射上。

ServletHolder holderPwd = new ServletHolder("default", DefaultServlet.class);
holderPwd.setInitParameter("dirAllowed", "true");
scch.addServlet(holderPwd, "/"); // <-- there should always be at least one at "/"

如果您需要多个

DefaultServlet
,请阅读过去的答案:https://stackoverflow.com/a/20223103/775715

另请参阅有关此主题的最新码头示例。

接下来,

ServletContextHandler
不能有带有全局符号的上下文路径。

这很糟糕,除非您以某种方式在 URI 路径本身中发送“*”,否则不会使用。

sch = new ServletContextHandler();
sch.setContextPath("/*"); // <-- this will only map if URI path is exactly `/*`

最后,如果您希望 Websocket 处于

/
状态,则不要使用
WebSocketServlet
,因为这会覆盖
DefaultServlet
行为,这不是您想要的。

请使用

WebSocketUpgradeFilter
,因为这不会干扰其他非 Websocket 请求的
/
/*
请求。

// Add the websocket filter
JettyWebSocketServletContainerInitializer.configure(sch, (context, configurator) ->
{
    configurator.setIdleTimeout(Duration.ofMillis(5000));
    configurator.addMapping("/", (req, res) -> {
        Session s = new Session(req);
        sessionManager.add(s);
        return s;
    });
});

参见示例

最后,你的设置太复杂了。

只需 1 个

ServletContextHandler
和 url 模式的混合,您就可以完成您想做的一切。

// This is Jetty 12 code, against the ee10 environment.

ServletContextHandler sch = new ServletContextHandler();
sch.setContextPath("/");
Resource baseResource = ResourceFactory.of(sch).newClassLoaderResource("cfg");
if (!Resources.isReadableDirectory(baseResource))
    throw new FileNotFoundException("Unable to find base resource");
sch.setBaseResourceBase(baseResource);

sch.setWelcomeFiles(new String[]{"websocket.html"});
sch.addServlet(new ServletHolder(new ModelServlet(model)), "/model/*");

Resource webResource = ResourceFactory.of(sch).newClassLoaderResource("web");
if (!Resources.isReadableDirectory(webResource))
    throw new FileNotFoundException("Unable to find web resource");

ServletHolder holderWeb = new ServletHolder("static-web", DefaultServlet.class);
holderWeb.setInitParameter("baseResource", webResource.getURI().toASCIIString());
holderWeb.setInitParameter("dirAllowed", "true");
holderWeb.setInitParameter("pathInfoOnly", "true");
sch.addServlet(holderWeb, "/web/*");

JettyWebSocketServletContainerInitializer.configure(sch, (context, configurator) ->
{
    configurator.setIdleTimeout(Duration.ofMillis(5000));
    configurator.addMapping("/ws", (req, res) -> {
        Session s = new Session(req);
        sessionManager.add(s);
        return s;
    });
});

server.setHandler(sch);
© www.soinside.com 2019 - 2024. All rights reserved.