Spring WebSocket 404錯(cuò)誤的解決方法
近來(lái)學(xué)習(xí) Spring WebSocket 時(shí)按照 Spring IN ACTION 中示例編寫代碼,運(yùn)行時(shí)瀏覽器報(bào)404 錯(cuò)誤
WebSocket connection to 'ws://localhost/websocket/marco' failed: Error during WebSocket handshake: Unexpected response code: 404

按照 Spring IN ACTION 中步驟:
首先,繼承 AbstractWebSocketHandler,重載以下 3 個(gè)方法:
- handleTextMessage – 處理文本類型消息
- afterConnectionEstablished – 新連接建立后調(diào)用
- afterConnectionClosed – 連接關(guān)閉后調(diào)用
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
public class MarcoHandler extends AbstractWebSocketHandler {
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("Received message: " + message.getPayload());
Thread.sleep(2000);
session.sendMessage(new TextMessage("Polo!"));
}
@Override
public void afterConnectionEstablished(WebSocketSession session) {
System.out.println("Connection established!");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
System.out.println("Connection closed. Status: " + status);
}
}
其次,使用 JavaConfig 啟用 WebSocket 并映射消息處理器
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(marcoHandler(), "/marco");
}
@Bean
public MarcoHandler marcoHandler() {
return new MarcoHandler();
}
}
最后,編寫前端 JS 代碼發(fā)起連接請(qǐng)求及后續(xù)消息交互
var url = 'ws://' + window.location.host + '/websocket/marco';
var sock = new WebSocket(url);
sock.onopen = function() {
console.log('Opening');
sock.send('Marco!');
};
sock.onmessage = function(e) {
console.log('Received Message: ', e.data);
setTimeout(function() {
sayMarco()
}, 2000);
};
sock.onclose = function() {
console.log('Closing');
};
function sayMarco() {
console.log('Sending Marco!');
sock.send('Marco!');
}
部署后打開瀏覽器運(yùn)行,直接報(bào) 404 錯(cuò)誤

上網(wǎng)搜索了一晚上解決方案,包括參考 stackoverflow.com 上的經(jīng)驗(yàn)都未解決該問(wèn)題,直到查看到以下文章:
Spring集成webSocket頁(yè)面訪問(wèn)404問(wèn)題的解決方法
在此自己也做個(gè)記錄避免以后遺忘。
WebSocket 實(shí)質(zhì)上借用 HTTP 請(qǐng)求進(jìn)行握手,啟用 Spring WebSocket 需要在 org.springframework.web.servlet.DispatcherServlet 里配置攔截此請(qǐng)求。
以下是解決步驟:
首先,修改 WebSocketConfig 類定義,在類上添加 @Configuration 注解,表明該類以 JavaConfig 形式用作 bean 定義的源(相當(dāng)于 XML 配置中的 <beans> 元素)。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(marcoHandler(), "/marco");
}
@Bean
public MarcoHandler marcoHandler() {
return new MarcoHandler();
}
}
其次,使用 JavaConfig 配置 DispatcherServlet,繼承org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer ,重載以下 3 個(gè)方法:
- getRootConfigClasses – 返回帶有 @Configuration 注解的類將會(huì)用來(lái)配置 ContextLoaderListener 創(chuàng)建的應(yīng)用上下文中的 bean
- getServletConfigClasses – 返回帶有 @Configuration 注解的類將會(huì)用來(lái)定義 DispatcherServlet 應(yīng)用上下文中的 bean
- getServletMappings – 將一個(gè)或多個(gè)路徑映射到 DispatcherServlet 上
實(shí)際上,如果只需要 Spring WebSocket 生效,則只需要在 getServletConfigClasses 方法中返回用來(lái)定義 DispatcherServlet 應(yīng)用上下文中的 bean
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebSocketInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebSocketConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
重新部署后代開瀏覽器運(yùn)行成功
客戶端消息

服務(wù)器消息

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Idea SpringBoot搭建SpringCloud的準(zhǔn)備工作(推薦)
這篇文章主要介紹了Idea SpringBoot搭建SpringCloud的準(zhǔn)備工作(推薦),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
如何在maven本地倉(cāng)庫(kù)中添加oracle的jdbc驅(qū)動(dòng)
文章介紹了在Maven項(xiàng)目中添加Oracle數(shù)據(jù)庫(kù)驅(qū)動(dòng)ojdbc5時(shí)遇到的問(wèn)題以及解決問(wèn)題的兩種方法,方法一為簡(jiǎn)單粗暴,但沒有體現(xiàn)Maven倉(cāng)庫(kù)的作用,需要手動(dòng)管理jar包,方法二為在Maven本地倉(cāng)庫(kù)中添加Oracle的JDBC驅(qū)動(dòng),過(guò)程較為繁瑣,但配置一次后可以多次使用2024-11-11
java WebSocket的實(shí)現(xiàn)以及Spring WebSocket示例代碼
本篇文章主要介紹了java WebSocket的實(shí)現(xiàn)以及Spring WebSocket,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-01-01
Java實(shí)現(xiàn)LeetCode(報(bào)數(shù))
這篇文章主要介紹了Java實(shí)現(xiàn)LeetCode(報(bào)數(shù)),本文通過(guò)使用java實(shí)現(xiàn)leetcode的報(bào)數(shù)題目和實(shí)現(xiàn)思路分析,需要的朋友可以參考下2021-06-06
JavaFX 監(jiān)聽窗口關(guān)閉事件實(shí)例詳解
這篇文章主要介紹了JavaFX 監(jiān)聽窗口關(guān)閉事件實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05
Java讀取json數(shù)據(jù)并存入數(shù)據(jù)庫(kù)的操作代碼
很多朋友問(wèn)大佬們JAVA怎么把json存入數(shù)據(jù)庫(kù)啊,這一問(wèn)題就把我難倒了,糾結(jié)如何操作呢,下面小編把我的經(jīng)驗(yàn)分享給大家,感興趣的朋友一起看看吧2021-08-08
Java實(shí)現(xiàn)短信驗(yàn)證碼和國(guó)際短信群發(fā)功能的示例
本篇文章主要介紹了Java實(shí)現(xiàn)短信驗(yàn)證碼和國(guó)際短信群發(fā)功能的示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02

