Spring websocket瀏覽器連接時出現404錯誤


1、場景

在用websocket做一個簡單的數據導入頁面同步顯示后台進度功能的時候,瀏覽器出現連接不上的錯誤:
WebSocket connection to 'ws://localhost:8080/project/marco' failed: Error during WebSocket handshake: Unexpected response code: 404

網上有很種導致404的情況,但是都沒有用,我在這里記錄一下我的情況。

2、解決過程

spring-websocket.xml的配置:

<websocket:handlers>
<websocket:mapping handler="messageHandler" path="/marco" />
<websocket:handshake-interceptors>
  <bean class="com.project.websocket.HandshakeInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>

<bean id="messageHandler" class="com.project.websocket.MessageHandler"/>

查看打印的INFO級別日志,根據spring的啟動信息我們可以看到:

2017-02-09 21:57:40,559 INFO  [springframework.web.servlet.handler.SimpleUrlHandlerMapping] - Mapped URL path [/marco] onto handler of type [class org.springframework.web.socket.server.support.WebSocketHttpRequestHandler]

WebSocketHttpRequestHandler通過SimpleUrlHandlerMapping注冊了/marco地址,那應該是沒錯的啊,難道是客戶端js的錯誤?

var websocket = new WebSocket('ws://' + window.location.host + '/project/marco');

地址好像也沒錯啊,和Spring in Action4里面的例子一樣的啊。
為什么地址沒有映射到/marco?先看看DispatchServlet的handlerMappings有沒有/marco先吧。

斷點DispatchServlet的doDispatch()方法,隨便發起一個請求:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    ......
	// Determine handler for the current request.
	mappedHandler = getHandler(processedRequest);
	if (mappedHandler == null || mappedHandler.getHandler() == null) {
		noHandlerFound(processedRequest, response);
		return;
	}
    ......
}

進入getHandler(processedRequest)

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	for (HandlerMapping hm : this.handlerMappings) {
		if (logger.isTraceEnabled()) {
			logger.trace(
					"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		HandlerExecutionChain handler = hm.getHandler(request);
		if (handler != null) {
			return handler;
		}
	}
	return null;
}

我們看一下handlerMappings里面的內容,不知道你們有沒有找到/marco,反正我是沒找到。
言下之意,/marco沒注冊到?

沒辦法,我們斷點SimpleUrlHandlerMapping的registerHandlers()方法和DispatchServlet的initHandlerMappings()方法。

我們看到SimpleUrlHandlerMapping的registerHandlers()先被執行。

最后退出registerHandlers()方法,F6一路下來,從WebApplicationObjectSupport的initApplicationContext()方法中可以看到:

  • context.beanFactory.beanDefintionMap中包含[org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0->RootBeanDefintion]
  • 而且context.beanFactory.singletonObjects也包含了注冊了/marco的SimpleUrlHandlerMapping實例。
  • 此時的context.configLocations是classpath:spring-context.xml

DispatchServlet的initHandlerMappings()后被執行,我們來看這段:

// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
Map<String, HandlerMapping> matchingBeans =
    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

然而,在matchingBeans沒有找到我們要的注冊了/marco的SimpleUrlHandlerMapping。此時的context.configLocations是classpath*:spring-servlet.xml

來到這里,你大概知道就是你的spring-websocket.xml放錯位置啦。

3、解決辦法

如果你的web.xml分開加載spring-context和spring-servlet的話,請將spring-websocket的資源文件放到spring-servlet上加載。
注意:在spring-context加載的時候,你的messageHandler應該是還沒有初始化,請不要注入到某個service上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM