WebSocket 实时通知机制。
在高并发、异步下单场景中,它是提升用户体验、降低轮询压力的关键组件。
接下来会从原理讲清楚,再结合“秒杀活动”落地展示完整的前后端交互与代码实现(Java Spring Boot + 前端示例)。
一、WebSocket 是什么?
WebSocket 是一种在浏览器和服务器之间建立「全双工、持久连接」的通信协议。
与传统 HTTP 不同,HTTP 是短连接、请求响应式的;而 WebSocket 建立连接后,服务器可以主动推送消息给客户端,不需要客户端轮询。
🔁 对比传统 HTTP 轮询
| 特点 | HTTP 轮询 | WebSocket |
|---|---|---|
| 连接模式 | 短连接,请求-响应 | 持久连接,双向通信 |
| 服务器能否主动发消息 | ❌ 不能 | ✅ 可以 |
| 性能 | 频繁请求,压力大 | 长连接,轻量、实时 |
| 适用场景 | 请求量小、实时性低 | 聊天、订单状态、秒杀、行情推送 |
二、在「秒杀活动」中为什么用 WebSocket?
在你的秒杀设计中:
-
用户点击“立即抢购” → 系统用 Redis + MQ 异步下单;
-
请求立即返回
"QUEUED"状态; -
后端在队列消费者落单后,才知道成功或失败。
如果不用 WebSocket:
-
用户只能轮询
GET /seckill/status?messageId=...; -
并发量高时,会造成 Web 层 + Redis + DB 压力。
如果用 WebSocket:
-
用户请求秒杀后,保持 WebSocket 长连接;
-
后端消费者落单完成时,通过 WebSocket 通道主动推送订单状态变更;
-
用户即时看到结果,不需要反复刷新。
👉 实时、节流、省资源。
三、WebSocket 在秒杀系统中的使用流程(图解)
┌──────────────────────┐│ 浏览器端 ││ 1. 建立 WebSocket ││ 2. 发送秒杀请求 ││ 3. 等待推送结果 │└──────────┬───────────┘│WebSocket 连接│┌──────────▼──────────┐│ 秒杀服务 (Spring) ││ - 维护连接映射表 ││ - 通过 MQ 消费结果 ││ - 推送状态到客户端 │└──────────┬───────────┘│MQ/Rabbit│┌──────────▼──────────┐│ 消费者服务 ││ - 创建订单 ││ - 发送结果通知 │└──────────────────────┘
四、详细实现(Java + 前端)
🔹 前端实现(示例)
假设前端是一个简单的 Vue / HTML 页面。
<!DOCTYPE html> <html> <head><title>秒杀活动</title> </head> <body><h2>秒杀活动</h2><button id="buyBtn">立即抢购</button><div id="status"></div><script>const userId = "user_123";const ws = new WebSocket(`ws://localhost:8080/ws/seckill/${userId}`); ws.onopen = () => {console.log("✅ WebSocket connected");};ws.onmessage = (event) => {const msg = JSON.parse(event.data);if (msg.type === "ORDER_STATUS") {document.getElementById("status").innerText = "订单状态: " + msg.status;}};document.getElementById("buyBtn").onclick = async () => {const res = await fetch("/api/seckill/buy?eventId=1001&userId=" + userId, {method: "POST"});const data = await res.json();document.getElementById("status").innerText = "请求结果: " + data.status;};</script> </body> </html>
说明:
-
页面在加载时与服务器建立 WebSocket 长连接;
-
当用户点击“立即抢购”后,发起 HTTP 下单请求;
-
后端在订单异步完成后,通过 WebSocket 主动推送消息;
-
前端即时更新显示。
🔹 后端实现(Spring Boot)
我们需要三个部分:
-
WebSocket 服务端(负责连接与推送)
-
秒杀请求 Controller(发起秒杀逻辑)
-
订单消费者(异步落单后推送结果)
1️⃣ WebSocket 配置与服务端类
// WebSocketConfig.java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new SeckillWebSocketHandler(), "/ws/seckill/{userId}").setAllowedOrigins("*"); // 生产环境记得做白名单 } }
// SeckillWebSocketHandler.java @Component public class SeckillWebSocketHandler extends TextWebSocketHandler {// 存储所有用户连接(简单实现,可换为 Redis + Channel 分布式映射)private static final Map<String, WebSocketSession> userSessions = new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) {String userId = getUserId(session);userSessions.put(userId, session);System.out.println("用户 " + userId + " 已连接");}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) {String userId = getUserId(session);userSessions.remove(userId);System.out.println("用户 " + userId + " 已断开");}private String getUserId(WebSocketSession session) {return session.getUri().getPath().split("/ws/seckill/")[1];}public void sendMessageToUser(String userId, String message) {WebSocketSession session = userSessions.get(userId);if (session != null && session.isOpen()) {try {session.sendMessage(new TextMessage(message));} catch (IOException e) {e.printStackTrace();}}} }
2️⃣ 秒杀 Controller(异步下单 + 即时返回)