【问题标题】:WebSocket application doesn't work properly when deployed on Tomcat8 serverWebSocket 应用程序在 Tomcat8 服务器上部署时无法正常工作
【发布时间】:2016-04-21 20:53:49
【问题描述】:

问题

我正在尝试对源代码进行最小更改来运行此示例:https://spring.io/guides/gs/messaging-stomp-websocket/

我已经设法使用 Eclipse 和 Maven 以及终端窗口再次使用 maven 运行它。我还设法将它打包成一个 .war 文件并使用java -jar myfile.war 在终端中运行它在这些情况下按预期工作,即 localhost:8080 显示简单的界面,它连接并在同一个窗口中返回一个问候语。当我将 .war 文件部署到我在 RaspberryPi 上运行的 tomcat8 服务器时,问题就出现了。在这种情况下,index.html 会显示,但“连接”按钮什么也不做,这让我相信这是某种与 javascript 相关的问题。服务器工作正常,顺便说一句,我在上面部署了其他东西。

我尝试过的事情

  • 编辑了 .war 存档,使 index.html 和 .js 文件位于 WEB-INF 目录之外,以便外界可以访问它们。问题仍然存在。
  • 将 index.html 中对 .js 文件的脚本引用更改为

<script src="http://cdn.sockjs.org/sockjs-0.3.4.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.js"></script>

以便它们可以通过 CDN 传送,以防 .war 文件出现任何问题。问题依然存在。

  • 为 servlet 添加了额外的功能,以便它在不同的目录中显示一些数据,以确保它正常工作,这不是 .war 文件的问题。看起来不错,但上述问题显然仍然存在。

代码

入口点

@SpringBootApplication
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

将返回的问候。

public class Greeting {

    private String content;

    public Greeting(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }
}

控制器

@Controller
public class GreetingController {


    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) throws Exception {
        Thread.sleep(3000); // simulated delay
        return new Greeting("Hello, " + message.getName() + "!");
    }

}

要发送的消息

public class HelloMessage {

    private String name;

    public String getName() {
        return name;
    }

}

WebSocket 配置

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/hello").withSockJS();
    }

}

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Hello WebSocket</title>
    <script src="sockjs-0.3.4.js"></script>
    <script src="stomp.js"></script>
    <script>
        var stompClient = null;
        
        function setConnected(connected) {
            document.getElementById('connect').disabled = connected;
            document.getElementById('disconnect').disabled = !connected;
            document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
            document.getElementById('response').innerHTML = '';
        }
        
        function connect() {
            var socket = new SockJS('/hello');
            stompClient = Stomp.over(socket);            
            stompClient.connect({}, function(frame) {
                setConnected(true);
                console.log('Connected: ' + frame);
                stompClient.subscribe('/topic/greetings', function(greeting){
                    showGreeting(JSON.parse(greeting.body).content);
                });
            });
        }
        
        function disconnect() {
            if (stompClient != null) {
                stompClient.disconnect();
            }
            setConnected(false);
            console.log("Disconnected");
        }
        
        function sendName() {
            var name = document.getElementById('name').value;
            stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
        }
        
        function showGreeting(message) {
            var response = document.getElementById('response');
            var p = document.createElement('p');
            p.style.wordWrap = 'break-word';
            p.appendChild(document.createTextNode(message));
            response.appendChild(p);
        }
    </script>
</head>
<body onload="disconnect()">
<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being enabled. Please enable
    Javascript and reload this page!</h2></noscript>
<div>
    <div>
        <button id="connect" onclick="connect();">Connect</button>
        <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button>
    </div>
    <div id="conversationDiv">
        <label>What is your name?</label><input type="text" id="name" />
        <button id="sendName" onclick="sendName();">Send</button>
        <p id="response"></p>
    </div>
</div>
</body>
</html>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-messaging-stomp-websocket</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.3.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <packaging>war</packaging>
</project>

上次部署的日志

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.3.3.RELEASE)

2016-04-21 22:39:51.727  INFO 18022 --- [o-8080-exec-129] hello.Application                        : Starting Application on raspberrypi with PID 18022 (/var/lib/tomcat8/webapps/gs-messaging-stomp-websocket-0.1.0/WEB-INF/classes/hello/Application.class started by tomcat8 in /var/lib/tomcat8)
2016-04-21 22:39:51.800  INFO 18022 --- [o-8080-exec-129] hello.Application                        : No active profile set, falling back to default profiles: default
2016-04-21 22:39:52.752  INFO 18022 --- [o-8080-exec-129] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@167fc4: startup date [Thu Apr 21 22:39:52 EEST 2016]; root of context hierarchy
2016-04-21 22:40:09.630  INFO 18022 --- [o-8080-exec-129] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanNameViewResolver' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter; factoryMethodName=beanNameViewResolver; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter.class]]
2016-04-21 22:40:16.208  INFO 18022 --- [o-8080-exec-129] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 23468 ms
2016-04-21 22:40:30.525  INFO 18022 --- [o-8080-exec-129] b.a.w.TomcatWebSocketContainerCustomizer : NonEmbeddedServletContainerFactory detected. Websockets support should be native so this normally is not a problem.
2016-04-21 22:40:40.343  INFO 18022 --- [o-8080-exec-129] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2016-04-21 22:40:40.360  INFO 18022 --- [o-8080-exec-129] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'errorPageFilter' to: [/*]
2016-04-21 22:40:40.363  INFO 18022 --- [o-8080-exec-129] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-04-21 22:40:40.366  INFO 18022 --- [o-8080-exec-129] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-04-21 22:40:40.369  INFO 18022 --- [o-8080-exec-129] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-04-21 22:40:40.372  INFO 18022 --- [o-8080-exec-129] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'requestContextFilter' to: [/*]
2016-04-21 22:40:41.904  INFO 18022 --- [o-8080-exec-129] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService  'clientInboundChannelExecutor'
2016-04-21 22:40:42.137  INFO 18022 --- [o-8080-exec-129] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService  'clientOutboundChannelExecutor'
2016-04-21 22:40:42.743  INFO 18022 --- [o-8080-exec-129] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService  'messageBrokerTaskScheduler'
2016-04-21 22:40:44.228  INFO 18022 --- [o-8080-exec-129] o.s.w.s.s.s.WebSocketHandlerMapping      : Mapped URL path [/hello/**] onto handler of type [class org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler]
2016-04-21 22:40:44.635  INFO 18022 --- [o-8080-exec-129] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService  'brokerChannelExecutor'
2016-04-21 22:40:49.712  INFO 18022 --- [o-8080-exec-129] .WebSocketAnnotationMethodMessageHandler : Mapped "{[/hello],messageType=[MESSAGE]}" onto public hello.Greeting hello.GreetingController.greeting(hello.HelloMessage) throws java.lang.Exception
2016-04-21 22:40:57.059  INFO 18022 --- [o-8080-exec-129] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@167fc4: startup date [Thu Apr 21 22:39:52 EEST 2016]; root of context hierarchy
2016-04-21 22:40:58.966  INFO 18022 --- [o-8080-exec-129] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2016-04-21 22:40:58.993  INFO 18022 --- [o-8080-exec-129] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2016-04-21 22:40:59.092  INFO 18022 --- [o-8080-exec-129] o.s.w.s.c.a.WebMvcConfigurerAdapter      : Adding welcome page: ServletContext resource [/index.html]
2016-04-21 22:40:59.622  INFO 18022 --- [o-8080-exec-129] o.s.w.s.handler.SimpleUrlHandlerMapping  : Root mapping to handler of type [class org.springframework.web.servlet.mvc.ParameterizableViewController]
2016-04-21 22:40:59.948  INFO 18022 --- [o-8080-exec-129] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-04-21 22:40:59.950  INFO 18022 --- [o-8080-exec-129] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-04-21 22:41:01.167  INFO 18022 --- [o-8080-exec-129] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2016-04-21 22:41:06.289  INFO 18022 --- [o-8080-exec-129] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2016-04-21 22:41:06.561  INFO 18022 --- [o-8080-exec-129] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 2147483647
2016-04-21 22:41:06.570  INFO 18022 --- [o-8080-exec-129] o.s.m.s.b.SimpleBrokerMessageHandler     : Starting...
2016-04-21 22:41:06.578  INFO 18022 --- [o-8080-exec-129] o.s.m.s.b.SimpleBrokerMessageHandler     : BrokerAvailabilityEvent[available=true, SimpleBrokerMessageHandler [DefaultSubscriptionRegistry[cache[0 destination(s)], registry[0 sessions]]]]
2016-04-21 22:41:06.597  INFO 18022 --- [o-8080-exec-129] o.s.m.s.b.SimpleBrokerMessageHandler     : Started.
2016-04-21 22:41:06.830  INFO 18022 --- [o-8080-exec-129] hello.Application                        : Started Application in 93.812 seconds (JVM running for 2602144.954)
Apr 21, 2016 10:41:07 PM org.apache.catalina.startup.HostConfig deployWAR
INFO: Deployment of web application archive /var/lib/tomcat8/webapps/gs-messaging-stomp-websocket-0.1.0.war has finished in 137,294 ms
2016-04-21 22:41:31.098  INFO 18022 --- [o-8080-exec-131] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2016-04-21 22:41:31.455  INFO 18022 --- [o-8080-exec-131] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 355 ms
2016-04-21 22:41:44.554  INFO 18022 --- [MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats    : WebSocketSession[0 current WS(0)-HttpStream(0)-HttpPoll(0), 0 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], outboundChannelpool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
2016-04-21 23:11:44.549  INFO 18022 --- [MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats    : WebSocketSession[0 current WS(0)-HttpStream(0)-HttpPoll(0), 0 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], outboundChannelpool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 1]
2016-04-21 23:41:44.549  INFO 18022 --- [MessageBroker-1] o.s.w.s.c.WebSocketMessageBrokerStats    : WebSocketSession[0 current WS(0)-HttpStream(0)-HttpPoll(0), 0 total, 0 closed abnormally (0 connect failure, 0 send limit, 0 transport error)], stompSubProtocol[processed CONNECT(0)-CONNECTED(0)-DISCONNECT(0)], stompBrokerRelay[null], inboundChannel[pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], outboundChannelpool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0], sockJsScheduler[pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 2]

链接到我的 .war 文件

http://s000.tinyupload.com/index.php?file_id=67742984079178858914

最后的想法

再次,通过消除过程,要么 .js 库没有正确导入,要么我的服务器的 WebSocket 支持有问题。我真的坚持这一点,任何和所有的帮助将不胜感激。

【问题讨论】:

  • Tomcat 8 的哪个版本? WebSocket 实现在 8.0.x 的各种版本中发生了巨大变化。一定要尝试最新的。仅供参考,Tomcat 8.5 和 9 中的实现可能会再次发生变化(还不确定细节,两者都是预发布版)。
  • Basil Bourque,Tomcat 版本:Apache Tomcat/8.0.14 (Debian); JVM:1.8.0_65-b17; JVM:供应商甲骨文公司;操作系统名称:Linux;操作系统版本:4.1.18+;操作系统架构:arm
  • 如果做 WebSocket 工作,你肯定需要更新到当前的 Tomcat 8.0.x。阅读发行说明,了解有关重大变化的信息。

标签: javascript java eclipse spring maven


【解决方案1】:

所以基本上可能发生的情况是,一旦您部署为服务,您的所有路径都会有点偏离,所以假设您有链接显示 &lt;a href="/home" &gt; home &lt;/a&gt; 它可以在本地工作,但不能在服务器上工作,因为您的应用程序 URL 现在是 host:8080/appName/ 并且当您使用 /home 引用任何内容而不是将您带到 host:8080/appName/home 时,它​​将需要您到主机:8080/home,此时它的 URL 已损坏。所以我认为你可以通过在这里改变你的 /hello 来解决你的问题

 function connect() {
            var socket = new SockJS('hello');
            stompClient = Stomp.over(socket);            
            stompClient.connect({}, function(frame) {
                setConnected(true);
                console.log('Connected: ' + frame);
                stompClient.subscribe('/topic/greetings', function(greeting){
                    showGreeting(JSON.parse(greeting.body).content);
                });
            });
        }

【讨论】:

  • 所以,你是说我应该这样做: var socket = new SockJS('/myServletName/hello'); ... .. stompClient.subscribe('/myServletName/topic/greetings', function(greeting)
  • @olexity 我遇到了同样的问题,我对您的解决方案进行了更改。我将const socket = new SockJS('/broadcast') 更改为:const socket = new SockJS('broadcast') 这将套接字端点的绝对路径更改为相对路径。当 .war 文件部署到 tomcat 时,它不是 ROOT 应用程序 - 它将从 // 为 .war 应用程序提供服务
【解决方案2】:

我尝试了 spring guides 示例,它与 Google chrome 版本 54.0.2840.100(64 位)完美配合

链接:https://github.com/spring-guides/gs-messaging-stomp-websocket/tree/master/complete

当我快速看到时,我发现您缺少以下依赖项

<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>webjars-locator</artifactId>
</dependency>
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>sockjs-client</artifactId>
    <version>1.0.2</version>
</dependency>
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>stomp-websocket</artifactId>
    <version>2.3.3</version>
</dependency>
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>bootstrap</artifactId>
    <version>3.3.7</version>
</dependency>
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>jquery</artifactId>
    <version>3.1.0</version>
</dependency>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 2021-05-25
    • 2015-10-17
    • 2013-05-21
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多