WebSocket
WebSocket 是一种计算机通信协议,用于在Web应用程序中实现双向通信。它允许服务器和客户端之间建立持久连接,并且可以通过单个网络套接字进行全双工通信。与传统的HTTP请求-响应模型不同,WebSocket 使用事件驱动的模式,可以实时地在服务器和客户端之间传输数据。
WebSocket 协议的特点包括:
- • 建立持久连接:WebSocket 连接在创建后保持打开状态,而不需要每次通信都重新建立连接。这降低了通信的延迟和资源消耗。
- • 全双工通信:服务器和客户端可以同时发送和接收数据,实现真正的双向通信。这使得服务器可以主动推送数据给客户端,而不仅仅是在请求时响应数据。
- • 低延迟:由于 WebSocket 连接始终保持打开状态,消息的传输延迟较小。这对于实时应用程序(如聊天应用、股票市场数据等)非常重要。
- • 跨域支持:WebSocket 协议支持跨域通信,即在不同域名或端口的服务器之间进行通信。
WebSocket 在 Web 应用程序中有广泛的应用,例如实时聊天应用、在线游戏、股票市场数据推送、在线协作等。它提供了一种更高效、实时的通信方式,同时减少了服务器和客户端之间的网络负载。
SpringBoot 整合 WebSocket
添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
WebSocketServer
package com.demo.websocket;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;/**
@ClassName: WebSocketServer.java
@ClassPath: com.demo.websocket.WebSocketServer.java
@Description: WebSocket
@Author: tanyp
@Date: 2023-09-05 10:35
**/
@Slf4j
@ServerEndpoint("/ws/{id}")
@Component
public class WebSocketServer {public static CopyOnWriteArraySet<WebSocketServer> sessionSet = new CopyOnWriteArraySet<>();
private Session session;
@Getter
private String id;@OnOpen
public void onOpen(Session session, @PathParam("id") String id) {
log.info("=======WebSocket 建立连接 id:{}==============", id);
this.session = session;
this.id = id;
sessionSet.add(this);
}@OnClose
public void onClose() {
sessionSet.remove(this);
}@OnError
public void onError(Session session, Throwable error, @PathParam("id") String id) {
log.error("========websocket错误================");
error.printStackTrace();
if (StringUtils.isNotBlank(id)) {
for (WebSocketServer ws : sessionSet) {
if (ws.id.equals(id)) {
sessionSet.remove(ws);
}
}
}
}public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}public synchronized static void sendMessage(@PathParam("id") String id, String message) throws IOException {
if (StringUtils.isNotBlank(id)) {
for (WebSocketServer ws : sessionSet) {
if (ws.id.equals(id)) {
ws.sendMessage(message);
}
}
}
}
}
推送数据
// websocket 推送数据
String prefix = "test-"; // 前缀
String sequence = "u0001"; // 唯一序列,例如:用户ID
String json = JSON.toJSONString({}); // JSON 数据
try {
WebSocketServer.sendMessage(prefix + sequence, json);
} catch (Exception e) {
log.error("websocket 推送数据异常:{}", e);
}
Vue3 使用 WebSocket
<script setup lang="ts">
import { onMounted, reactive,toRefs } from 'vue'const state = reactive({ socket: null, }) const {socket} = toRefs(state) onMounted(()=>{ webSocket() }) function webSocket(){ if ('WebSocket' in window) { // 与后端配置保持一致(IP + 端口 + "/ws/" + 前缀 + 唯一序列) state.socket = new WebSocket('ws:' + window.location.hostname+':8080/ws/test-u0001'); state.socket.onmessage = function (event:any) { // 接收数据,更具业务自行处理 console.log(event.data) } state.socket.onopen = function () { console.log('连接已建立') } state.socket.onclose = function () { console.log('连接已关闭') } state.socket.onerror = function () { console.log('连接异常,尝试重新连接') // webSocket(); } window.onbeforeunload = function () { state.socket.onclose(); } } }
</script>
注:一定确保 WebSocket 连接的地址与后端配置的地址相匹配(IP + 端口 + "/ws/" + 前缀 + 唯一序列)。例如:http://127.0.0.1/ws/test-u0001