一. 與HTTP對比
WebSocket 是一種在單個 TCP 連接上實現全雙工(雙向)通信的網絡協議,它解決了傳統 HTTP 協議 “請求 - 響應” 模式的局限性,讓客戶端(如瀏覽器)和服務器能建立持久連接,實現實時數據交互。
HTTP是短鏈接且單向通信,只有客戶端主動發請求,服務器才能被動響應,無法主動向客戶端推數據。WebSocket是長連接且支持雙向通信
WebSocket通過一次HTTP握手建立持久TCP連接,之后客戶端與服務器可基于該連接全雙工、實時雙向收發數據,無需反復建立連接。
二. WebSocket的關鍵特性
- 全雙工通信:客戶端和服務器可同時發送數據,無需等待對方響應。
- 持久連接:連接建立后長期保持,除非主動斷開(如客戶端關閉頁面、服務器重啟)。
- 跨域支持:WebSocket 本身支持跨域(類似 CORS),可通過?
Origin
?請求頭和服務器配置控制跨域權限。 - 支持二進制數據:不僅能傳文本(如 JSON),還能直接傳二進制數據(如圖片、音頻、視頻流),比 HTTP 傳輸二進制更高效。
- 自動重連(需手動實現):原生 WebSocket 不支持自動重連,實際項目中需通過代碼邏輯實現(如監聽?
onclose
?事件,延遲后重新發起連接)。
三.?WebSocket 的典型應用場景
只要涉及 “實時數據交互” 的場景,WebSocket 都是優選方案:
- 即時通訊:在線聊天(如微信網頁版、企業 IM)、客服對話。
- 實時通知:訂單狀態更新(如 “訂單已發貨”)、消息推送(如點贊提醒)。
- 實時數據展示:股票 / 數字貨幣行情、體育賽事比分、監控系統數據(如服務器 CPU 使用率)。
- 協同工具:多人在線文檔編輯(如騰訊文檔)、白板協作。
- 流媒體:低延遲的音視頻通話(如 WebRTC 基于 WebSocket 做信令交互)、直播彈幕。
四. 實現步驟
1.前端(瀏覽器原生API)
瀏覽器內置WebSocket對象,可直接發送連接和處理數據。
這里以一個簡單實現為例
<!DOCTYPE HTML>
<html>
<head><meta charset="UTF-8"><title>WebSocket Demo</title>
</head>
<body><input id="text" type="text" /><button onclick="send()">發送消息</button><button onclick="closeWebSocket()">關閉連接</button><div id="message"></div>
</body>
<script type="text/javascript">var websocket = null;var clientId = Math.random().toString(36).substr(2);//判斷當前瀏覽器是否支持WebSocketif('WebSocket' in window){//連接WebSocket節點websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);}else{alert('Not support websocket')}//連接發生錯誤的回調方法websocket.onerror = function(){setMessageInnerHTML("error");};//連接成功建立的回調方法websocket.onopen = function(){setMessageInnerHTML("連接成功");}//接收到消息的回調方法websocket.onmessage = function(event){setMessageInnerHTML(event.data);}//連接關閉的回調方法websocket.onclose = function(){setMessageInnerHTML("close");}//監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,防止連接還沒斷開就關閉窗口,server端會拋異常。window.onbeforeunload = function(){websocket.close();}//將消息顯示在網頁上function setMessageInnerHTML(innerHTML){document.getElementById('message').innerHTML += innerHTML + '<br/>';}//發送消息function send(){var message = document.getElementById('text').value;websocket.send(message);}//關閉連接function closeWebSocket() {websocket.close();}
</script>
</html>
2. 后端
2.1?導入WebSocket的maven坐標
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.2 導入WebSocket服務端組件WebSocketServer,用于和客戶端通信
/*** WebSocket服務*/
@Component // 交給 Spring 管理
@ServerEndpoint("/ws/{sid}")
//聲明這是一個 WebSocket 服務端,路徑為 /websocket/{sid}(支持路徑參數)
public class WebSocketServer {//存放會話對象private static Map<String, Session> sessionMap = new HashMap();/*** 連接建立成功調用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客戶端:" + sid + "建立連接");sessionMap.put(sid, session);}/*** 收到客戶端消息后調用的方法* @param message 客戶端發送過來的消息*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到來自客戶端:" + sid + "的信息:" + message);}/*** 連接關閉調用的方法* @param sid*/@OnClosepublic void onClose(@PathParam("sid") String sid) {System.out.println("連接斷開:" + sid);sessionMap.remove(sid);}/*** 群發* @param message*/public void sendToAllClient(String message) {Collection<Session> sessions = sessionMap.values();for (Session session : sessions) {try {//服務器向客戶端發送消息session.getBasicRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}
WebSocketServer的代碼格式基本就是這樣,可以根據需要自行修改。
2.3 導入配置類WebSocketConfiguration,注冊WebSocket的服務端組件
/*** WebSocket配置類,用于注冊WebSocket的Bean*/
@Configuration
public class WebSocketConfiguration {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}
前端和后端建立 WebSocket 連接的過程可分為 “握手” 和 “連接維持” 兩步:
- 握手階段:前端通過?
new WebSocket('ws://服務器地址')
?發起 HTTP 升級請求,攜帶?Upgrade: websocket
?等頭信息;后端驗證后返回?101 Switching Protocols
?響應,完成協議切換。 - 連接維持:握手成功后,TCP 連接保持持久狀態,雙方通過 WebSocket 幀格式直接雙向收發數據,直到某一方主動關閉連接。
核心流程:前端發 HTTP 請求(帶升級標識)→ 2. 后端驗證并返回 101 響應 → 3. 協議切換為 WebSocket → 4. 基于持久 TCP 連接雙向通信。
2.4 導入定時任務類WebSocketTask,定時向客戶端推送數據
這相當于一個案例,如何使用WebSocketServer。
@Component
public class WebSocketTask {@Autowiredprivate WebSocketServer webSocketServer;/*** 通過WebSocket每隔5秒向客戶端發送消息*/@Scheduled(cron = "0/5 * * * * ?")public void sendMessageToClient() {webSocketServer.sendToAllClient("這是來自服務端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));}
}
當我們想向前端頁面推送消息時WebSocketTask的方法sendMessageToClient,如果要傳遞一個對象,注意將其轉換成json格式,例如:
Map map = new HashMap();map.put("type", 2);//1表示來單提醒 2表示客戶催單map.put("orderId", id);map.put("content", "訂單號:" + orders.getNumber());String json = JSON.toJSONString(map);// 通過WebSocket向客戶端瀏覽器推送消息webSocketServer.sendToAllClient(json);