[英]WebSocket application doesn't work properly when deployed on Tomcat8 server
The Problem 问题
I'm trying to run this example with minimal changes in the source code: https://spring.io/guides/gs/messaging-stomp-websocket/ 我正在尝试以最小的源代码更改运行此示例: https : //spring.io/guides/gs/messaging-stomp-websocket/
I have managed to run it using Eclipse and Maven, as well as a terminal window, again, with maven. 我已经设法使用Eclipse和Maven以及终端窗口再次使用maven来运行它。 I've also managed to package it into a .war file and run it in terminal using
java -jar myfile.war
It works as expected in those cases, ie localhost:8080 displays the simple interface and it connects and returns a greeting in the same window. 我还设法将其打包成.war文件,并使用
java -jar myfile.war
在终端中运行。在这种情况下,它可以按预期工作,即localhost:8080显示简单的界面,并在其中连接并返回问候语同一窗口。 The problem comes when I deploy the .war file to a tomcat8 server I have running on my RaspberryPi. 当将.war文件部署到在RaspberryPi上运行的tomcat8服务器时,就会出现问题。 In that case, the index.html displays, but the "Connect" button does nothing, which leads me to believe this is some sort of javascript related issue.
在这种情况下,将显示index.html,但是“连接”按钮什么也不做,这使我相信这是与javascript相关的问题。 The server works fine, btw, I have other stuff deployed on it.
服务器工作正常,顺便说一句,我在上面部署了其他东西。
Things I've Tried 我尝试过的事情
<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>
so that they may be delivered over a CDN, in case there was any problem with the .war file. 因此,如果.war文件有任何问题,它们可以通过CDN交付。 The problem persists.
问题仍然存在。
Code 码
Entry point 入口点
@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);
}
}
Greeting that will be returned. 问候语将被返回。
public class Greeting {
private String content;
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
Controller 控制者
@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() + "!");
}
}
Message to be sent 要发送的消息
public class HelloMessage {
private String name;
public String getName() {
return name;
}
}
WebSocket configuration 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 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 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>
Log from last deployment 上次部署的日志
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: 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]
Link to my .war file 链接到我的.war文件
http://s000.tinyupload.com/index.php?file_id=67742984079178858914 http://s000.tinyupload.com/index.php?file_id=67742984079178858914
Final Thoughts 最后的想法
Again, by process of elimination, either the .js libraries aren't importing properly, or there is something wrong with my server's WebSocket support. 同样,通过消除过程,.js库未正确导入,或者服务器的WebSocket支持出现问题。 I'm really stuck on this one, any and all help would be appreciated.
我真的很坚持这一点,我们将不胜感激。
So basically what may be happening is that once you deploy to service all your paths are a little off, so lets say you have link that says <a href="/home" > home </a>
it will work on local but will not work on server because your application URL is now host:8080/appName/ and when you refer to anything with /home instead of taking you to host:8080/appName/home it will take you to host:8080/home, at which point its a broken url. 因此,基本上可能会发生的事情是,一旦部署到服务中,您的所有路径都会有些偏离,所以可以说您有一个链接,它表示
<a href="/home" > home </a>
可以在本地运行,但可以在服务器上不起作用,因为您的应用程序URL现在是host:8080 / appName /,并且当您使用/ home引用任何内容而不是将您带到host:8080 / appName / home时,它将带您到host:8080 / home将其指向损坏的网址。 So I think you can fix your issue by changing your /hello in here 因此,我认为您可以通过在此处更改/ 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);
});
});
}
I tried spring guides example it works perfectly fine with Google chrome Version 54.0.2840.100 (64-bit) 我尝试了春季指南示例,它与Google chrome版本54.0.2840.100(64位)完美配合
Link : https://github.com/spring-guides/gs-messaging-stomp-websocket/tree/master/complete 链接: https : //github.com/spring-guides/gs-messaging-stomp-websocket/tree/master/complete
when I saw quickly I found you missing below dependencies 当我很快看到我发现您缺少依赖项时
<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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.