Spring Websockets 在自定义应用程序上下文路径下不工作
Spring Websockets not working under custom application context path
我有使用 Spring 4.3.5 和 spring mvc - apache tiles 的应用程序。
我是按照这篇文章写聊天的https://spring.io/guides/gs/messaging-stomp-websocket/
一切正常,如果我的整个应用程序上下文路径是根,例如:http://example.com/我在 websocket
中收到以下帧
["SUBSCRIBE\nid:sub-0\ndestination:/chat-messages/TST\n\n\u0000"]
["SEND\ndestination:/chat/message/TST\ncontent-length:52\n\n{\"message\":\"\",\"username\":\"USER\",\"event\":\"ONLINE\"}\u0000"]
["MESSAGE\ndestination:/chat-messages/TST\ncontent-type:application/json;charset=UTF-8\nsubscription:sub-0\nmessage-id:x1jpjyes-1\ncontent-length:230\n\n{..SOME JSON CONTENT....}\u0000"]
问题是它停止工作,如果我添加一些应用程序上下文(我需要在我的服务器上这样做)
例如:http://example.com/my-app
没有收到消息 ,也没有发送消息
更新: 没有通过向目标前缀添加 servletContext.getContextPath() 来修复发送问题。
根据上下文,我只得到了这个:
["SUBSCRIBE\nid:sub-0\ndestination:/my-app/chat-messages/TST\n\n\u0000"]
["SEND\ndestination:/my-app/chat/message/TST\ncontent-length:52\n\n{\"message\":\"\",\"username\":\"USER\",\"event\":\"ONLINE\"}\u0000"]
这是我的配置:
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
private static final String TILES = "/WEB-INF/tiles/tiles.xml";
private static final String VIEWS = "/WEB-INF/views/**/views.xml";
private static final String RESOURCES_HANDLER = "/resources/";
private static final String RESOURCES_LOCATION = RESOURCES_HANDLER + "**";
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping requestMappingHandlerMapping = super
.requestMappingHandlerMapping();
requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
requestMappingHandlerMapping.setUseTrailingSlashMatch(false);
return requestMappingHandlerMapping;
}
@Bean
public TilesViewResolver configureTilesViewResolver() {
return new TilesViewResolver();
}
@Bean
public TilesConfigurer configureTilesConfigurer() {
TilesConfigurer configurer = new TilesConfigurer();
configurer.setDefinitions(TILES, VIEWS);
return configurer;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(RESOURCES_HANDLER).addResourceLocations(
RESOURCES_LOCATION);
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
WebSocketMesssageBroker
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Autowired
private ServletContext servletContext;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/chat-messages");
config.setApplicationDestinationPrefixes(servletContext.getContextPath() + "/chat");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat-websocket").withSockJS();
}
}
而且我有一个控制器来处理所有事情
@MessageMapping("/message/{projectId}")
@SendTo("/chat-messages/{projectId}")
public ChatResponse sendMessage(@DestinationVariable String projectId, MessageSent message) throw InterruptedException {
//Send reponse back like user online/offline or message posted
return new ChatResponse(chatMessage);
}
在 JSP 文件中我有以下 JS 调用
var socket = new SockJS('<c:url value="/chat-websocket/"/>');
stompClient.subscribe('<c:url value="/chat-messages/${chatProject.projectId}"/>', function (data) { ....SOME RESPONSE PROCESSING... });
stompClient.send("<c:url value="/chat/message/${chatProject.projectId}"/>", {}, JSON.stringify({.....PAYLOAD TO SEND ---}));
和web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<error-page>
<exception-type>org.springframework.security.web.authentication.rememberme.CookieTheftException</exception-type>
<location>/signin</location>
</error-page>
<error-page>
<location>/generalError</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
</web-app>
我确实怀疑这可能与 web.xml 中的磁贴或整个调度程序的配置或类似的东西有关:/
如果有提示会非常棒
我终于解决了这个问题。事实证明,每当我创建 SockJS 订阅者时,我都应该将相对路径作为参数传递,没有任何上下文
(我假设基础 websocket 打开 url 已经有正确的 url)
因此,为了正确接收订阅事件,我所要做的就是更改
stompClient.subscribe('<c:url value="/chat-messages/${chatProject.projectId}"/>', function (data) { ....SOME RESPONSE PROCESSING... });
对此:
stompClient.subscribe('/chat-messages/${chatProject.projectId}', function (data) { ....SOME RESPONSE PROCESSING... });
(没有一直返回上下文路径的 )
因此,每当我尝试使用
<c:url value="chat-messages/ID">
订阅聊天消息时,实际上我订阅的是:
my-app/chat-messages/ID
我的控制器和配置期待简单的相对聊天消息
这就是为什么在将 contextPath 添加到 WebSocketController setApplicationDestinationPrefixes 后,应用程序开始发送正确的消息
那几个小时我回不去了:)
我有使用 Spring 4.3.5 和 spring mvc - apache tiles 的应用程序。
我是按照这篇文章写聊天的https://spring.io/guides/gs/messaging-stomp-websocket/
一切正常,如果我的整个应用程序上下文路径是根,例如:http://example.com/我在 websocket
中收到以下帧["SUBSCRIBE\nid:sub-0\ndestination:/chat-messages/TST\n\n\u0000"]
["SEND\ndestination:/chat/message/TST\ncontent-length:52\n\n{\"message\":\"\",\"username\":\"USER\",\"event\":\"ONLINE\"}\u0000"]
["MESSAGE\ndestination:/chat-messages/TST\ncontent-type:application/json;charset=UTF-8\nsubscription:sub-0\nmessage-id:x1jpjyes-1\ncontent-length:230\n\n{..SOME JSON CONTENT....}\u0000"]
问题是它停止工作,如果我添加一些应用程序上下文(我需要在我的服务器上这样做)
例如:http://example.com/my-app
没有收到消息 ,也没有发送消息
更新: 没有通过向目标前缀添加 servletContext.getContextPath() 来修复发送问题。
根据上下文,我只得到了这个:
["SUBSCRIBE\nid:sub-0\ndestination:/my-app/chat-messages/TST\n\n\u0000"]
["SEND\ndestination:/my-app/chat/message/TST\ncontent-length:52\n\n{\"message\":\"\",\"username\":\"USER\",\"event\":\"ONLINE\"}\u0000"]
这是我的配置:
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
private static final String TILES = "/WEB-INF/tiles/tiles.xml";
private static final String VIEWS = "/WEB-INF/views/**/views.xml";
private static final String RESOURCES_HANDLER = "/resources/";
private static final String RESOURCES_LOCATION = RESOURCES_HANDLER + "**";
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping requestMappingHandlerMapping = super
.requestMappingHandlerMapping();
requestMappingHandlerMapping.setUseSuffixPatternMatch(false);
requestMappingHandlerMapping.setUseTrailingSlashMatch(false);
return requestMappingHandlerMapping;
}
@Bean
public TilesViewResolver configureTilesViewResolver() {
return new TilesViewResolver();
}
@Bean
public TilesConfigurer configureTilesConfigurer() {
TilesConfigurer configurer = new TilesConfigurer();
configurer.setDefinitions(TILES, VIEWS);
return configurer;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(RESOURCES_HANDLER).addResourceLocations(
RESOURCES_LOCATION);
}
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
WebSocketMesssageBroker
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Autowired
private ServletContext servletContext;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/chat-messages");
config.setApplicationDestinationPrefixes(servletContext.getContextPath() + "/chat");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat-websocket").withSockJS();
}
}
而且我有一个控制器来处理所有事情
@MessageMapping("/message/{projectId}")
@SendTo("/chat-messages/{projectId}")
public ChatResponse sendMessage(@DestinationVariable String projectId, MessageSent message) throw InterruptedException {
//Send reponse back like user online/offline or message posted
return new ChatResponse(chatMessage);
}
在 JSP 文件中我有以下 JS 调用
var socket = new SockJS('<c:url value="/chat-websocket/"/>');
stompClient.subscribe('<c:url value="/chat-messages/${chatProject.projectId}"/>', function (data) { ....SOME RESPONSE PROCESSING... });
stompClient.send("<c:url value="/chat/message/${chatProject.projectId}"/>", {}, JSON.stringify({.....PAYLOAD TO SEND ---}));
和web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<error-page>
<exception-type>org.springframework.security.web.authentication.rememberme.CookieTheftException</exception-type>
<location>/signin</location>
</error-page>
<error-page>
<location>/generalError</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<trim-directive-whitespaces>true</trim-directive-whitespaces>
</jsp-property-group>
</jsp-config>
</web-app>
我确实怀疑这可能与 web.xml 中的磁贴或整个调度程序的配置或类似的东西有关:/
如果有提示会非常棒
我终于解决了这个问题。事实证明,每当我创建 SockJS 订阅者时,我都应该将相对路径作为参数传递,没有任何上下文
(我假设基础 websocket 打开 url 已经有正确的 url)
因此,为了正确接收订阅事件,我所要做的就是更改
stompClient.subscribe('<c:url value="/chat-messages/${chatProject.projectId}"/>', function (data) { ....SOME RESPONSE PROCESSING... });
对此:
stompClient.subscribe('/chat-messages/${chatProject.projectId}', function (data) { ....SOME RESPONSE PROCESSING... });
(没有一直返回上下文路径的
因此,每当我尝试使用
<c:url value="chat-messages/ID">订阅聊天消息时,实际上我订阅的是:
my-app/chat-messages/ID我的控制器和配置期待简单的相对聊天消息
这就是为什么在将 contextPath 添加到 WebSocketController setApplicationDestinationPrefixes 后,应用程序开始发送正确的消息
那几个小时我回不去了:)