嵌入式Undertown同时部署websocket和servlet,不起作用

Posted

技术标签:

【中文标题】嵌入式Undertown同时部署websocket和servlet,不起作用【英文标题】:Embedded Undertown deploy websocket and servlet at same time, not work 【发布时间】:2016-02-15 08:45:01 【问题描述】:

我是使用 undertow 的新手,我正在开发一个独立的应用程序,将其用作嵌入式服务器。我希望我可以在我的嵌入式 undertow 中部署 web sockets、servlet 和 restfull htmls 服务。

到目前为止,我只使用 web 套接字和 servlet 完成了测试,每个单独的功能都正确的问题,但是如果我删除 servlet 页面,我不会从带有 HTML 和 javascript 的测试页面访问的 web 套接字部署它们nigun 测试运行没有错误。

这是我的代码:

    /*
     * Create the  appWebSocketDeploymentInfo and configure
     */
    WebSocketDeploymentInfo appWebSocketDeploymentInfo = new WebSocketDeploymentInfo();
    appWebSocketDeploymentInfo.setBuffers(new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16));
    appWebSocketDeploymentInfo.addEndpoint(WebSocketEndpoint1.class);
    appWebSocketDeploymentInfo.addEndpoint(WebSocketEndpoint2.class);

    /*
     * Create the  appDeploymentInfo and configure
     */
    DeploymentInfo appDeploymentInfo = Servlets.deployment()
                                    .setClassLoader(Server.class.getClassLoader())
                                    .setContextPath("/myapp)
                                    .setDeploymentName("app.war")
                                    .setResourceManager(new FileResourceManager(new File("src/main/webapp"), 1024))
                                    .addServlets(Servlets.servlet("HomeServlet", HomeServlet.class).addMapping("/home"))
                                    .setResourceManager(new ClassPathResourceManager(Server.class.getClassLoader(), Server.class.getPackage()))
                                    .addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, appWebSocketDeploymentInfo);

    /*
     * Create the deploymentManager
     */
    deploymentManager = Servlets.defaultContainer().addDeployment(appDeploymentInfo);

    /*
     * Deploy the app
     */
    deploymentManager.deploy();

    /*
     * Create the path handle
     */
    pathHandler = Handlers.path(Handlers.redirect("/myapp/home")).addPrefixPath("/myapp", deploymentManager.start());

    /*
     * Create the server
     */
    undertowServer = Undertow.builder().addHttpListener(DEFAULT_PORT, DEFAULT_IP).setHandler(pathHandler).build();

javascript日志错误是

WebSocket 连接到“ws://localhost:8080/fermat/node-channel”失败:WebSocket 握手期间出错:意外响应代码:404

【问题讨论】:

不是你的问题的真正答案,而是更多的提示:你有没有想过为此使用 Spring Boot ?它也支持 Undertow,并且会以自动方式处理您手动执行的操作。 谢谢,不过我对spring了解不多,实在不想用。 找到这个例子:github.com/fourcube/guice-undertow-websockets 【参考方案1】:

经过广泛的测试和研究,我得到了正确的配置和启动服务器的方法,还将添加对其他技术的支持,例如:

WebSocket 放心 焊接

我的最终代码

UndertowJaxrsServer server = new UndertowJaxrsServer();
Undertow.Builder serverBuilder = Undertow.builder().addHttpListener(DEFAULT_PORT, DEFAULT_IP);
ServletContainer servletContainer = Servlets.defaultContainer();

   /*
    * Create the App WebSocketDeploymentInfo and configure
    */
    WebSocketDeploymentInfo appWebSocketDeploymentInfo = new WebSocketDeploymentInfo();
    appWebSocketDeploymentInfo.setBuffers(new    ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16));
    appWebSocketDeploymentInfo.addEndpoint(WebSocketNodeChannelServerEndpoint.class);
    appWebSocketDeploymentInfo.addEndpoint(WebSocketClientChannelServerEndpoint.class);

    /*
     * Create the App ResteasyDeployment and configure
     */
    ResteasyDeployment deployment = new ResteasyDeployment();
    deployment.setApplicationClass(JaxRsActivator.class.getName());
    deployment.setInjectorFactoryClass("org.jboss.resteasy.cdi.CdiInjectorFactory");

    /*
     * Create the App DeploymentInfo and configure
     */
    DeploymentInfo appDeploymentInfo  = server.undertowDeployment(deployment, APP_NAME);
    appDeploymentInfo.setClassLoader(FermatEmbeddedNodeServer.class.getClassLoader())
                    .setContextPath(APP_NAME)
                    .setDeploymentName(WAR_APP_NAME)
                    .addServletContextAttribute(WebSocketDeploymentInfo.ATTRIBUTE_NAME, appWebSocketDeploymentInfo)
                    .addServlets(Servlets.servlet("HomeServlet", HomeServlet.class).addMapping("/home"))
                    .addListeners(Servlets.listener(org.jboss.weld.environment.servlet.Listener.class));

    server.deploy(appDeploymentInfo);
    server.start(serverBuilder);

Gradle 依赖项

compile 'io.undertow:undertow-core:1.3.6.Final'
compile 'io.undertow:undertow-servlet:1.3.6.Final'
compile 'io.undertow:undertow-websockets-jsr:1.3.6.Final'

compile 'org.jboss.resteasy:resteasy-undertow:3.0.13.Final'
compile 'org.jboss.resteasy:resteasy-cdi:3.0.13.Final'
compile 'org.jboss.weld.servlet:weld-servlet:2.3.1.Final'

compile 'javax:javaee-api:7.0'

【讨论】:

我已经尝试过您的方法,但似乎无法注入到 websocket 端点工作。这对你有用吗? 其实我在没有测试过的端点中使用依赖注入端RESTful WebService。 是的,REST 端点中的注入也适用于我。无法让它为 websocket 端点工作。看起来 websocket 规范没有指定与 CDI 的集成应该如何工作,哪些上下文在起作用,等等。 嘿,所以我能够实现类似的东西,你有什么解决 CDI 问题的方法吗?将 bean 注入 websocket serverendpoints 似乎没有按预期工作。

以上是关于嵌入式Undertown同时部署websocket和servlet,不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 jetty 中部署 webapps 和 websockets

Jetty 中的 JSR-356 javax websockets(嵌入式和非嵌入式)

WebSocket服务器(物联网下行通知神器)

如何在仍然使用 WebSocket 的同时运行 Gunicorn

tomcat7 spring boot应用程序中的websockets

嵌入式tomcat 8.0.21中的Spring websocket