本文将介绍前后端持久通信协议 – WebSocket。
一、什么是 WebSocket ?
在项目开发中,我们常常会遇到 “即时通信” 的需求。
实现方式有四种:
- 短轮询:
- 客户端重复发送 HTTP 请求
- 实时性较差(考虑网络资源消耗,两次请求之间必须留出一定时间)
- 长轮询:
- 客户端发送请求,持续等待
- 服务端接收请求后,有消息则立即返回,没有消息则将请求挂起,待有通知后立即返回
- 客户端接收请求响应后立即发起下一次请求
- 长连接:
- 通过 HTTP 1.1 中的 connection 字段进行长连接 (connection:keep-alive)
- 在依次 TCP 连接中可以进行多次请求,但每个请求仍然要单独发 header
- WebSocket:
HTML5 定义了 WebSocket 协议,客户端和服务器只需要完成依次握手,两者之间就可以建立持久的连接,并进行双向数据传输。
二、简单示例
1. 建立 SpringBoot 项目
略
2. 引入依赖
修改 pom.xml,修改如下:
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
|
3. 创建 WebSocket 配置类
1 2 3 4 5 6 7 8 9
| @Configuration public class WebSocketConfig {
@Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); }
}
|
4. 创建 WebSocket 服务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| @Component @ServerEndpoint("/websocket") public class WebSocketServer {
private static final Map<String, WebSocketServer> connections = new LinkedHashMap<>();
private Session session;
@OnOpen public void onOpen(Session session) { this.session = session; connections.put(session.getId(), this); }
@OnMessage public void onMessage(String message) { try { sendMessage(message); } catch (Exception e) { e.printStackTrace(); } }
@OnError public void onError(Throwable error) throws Throwable { throw error; }
@OnClose public void onClose() { connections.remove(session.getId()); }
public void sendMessage(String message) throws IOException { session.getBasicRemote().sendText(message); }
public static void broadcast(String message) { connections.forEach((k, v) -> { try { v.sendMessage(message); } catch (Exception e) { e.printStackTrace(); } }); } }
|
5. 增加群发接口
1 2 3 4 5 6 7 8
| @RestController public class BroadcastController {
@GetMapping("/broadcast") public void broadcast(){ WebSocketServer.broadcast("发布通知"); } }
|
6. 测试
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| let socket = new WebSocket("ws://localhost:8080/websocket")
socket.onerror = err => { console.log(err) }
socket.onopen = event => { console.log(event) }
socket.onmessage = event => { console.log(event) }
socket.onclose = () => { console.log("连接关闭") }
socket.send("hello")
socket.close()
|
三、认证问题
在开发中,可能遇到已登录系统但进行 WebSocket 连接失败的错误。
这是因为 WebSocket 是基于 TCP 的一种独立实现,需要单独进行身份认证。
有两种解决方法:
以 JWT 为例,将连接 url 改为:
1
| ws://localhost:8080/websocket?authorization=···
|
参考