实时通信
youlai-admin 使用 SSE(Server-Sent Events)实现服务器到客户端的实时推送。
为什么选择 SSE
| 对比项 | SSE | WebSocket |
|---|---|---|
| 通信方向 | 单向(服务端→客户端) | 双向 |
| 协议 | HTTP | WS/WSS |
| 断线重连 | 浏览器自动 | 需手动实现 |
| 适用场景 | 消息推送、通知 | 聊天、游戏 |
youlai-admin 的场景(字典同步、在线人数)只需要服务端推送,SSE 更简单。
架构
┌─────────────┐ HTTP GET ┌─────────────┐
│ 前端 │ ───────────────→ │ 后端 │
│ useSse │ │ SSE 控制器 │
│ │ ←─────────────── │ │
└─────────────┘ EventStream └─────────────┘
│
▼
┌─────────────┐
│ Redis │
│ Pub/Sub │
└─────────────┘前端实现
useSse Composable
typescript
import { useSse } from "@/composables";
const { isConnected, connect, on } = useSse();
// 建立连接
onMounted(() => connect());
// 订阅事件
on("dict-change", (data) => {
console.log("字典已更新:", data.dictCode);
});内置事件
| 事件名 | 说明 | 数据结构 |
|---|---|---|
dict-change | 字典变更 | { dictCode: string } |
online-count | 在线人数 | { count: number } |
后端实现
Java(Spring Boot)
java
@GetMapping("/api/v1/sse/connect")
public SseEmitter connect() {
SseEmitter emitter = new SseEmitter(0L);
// 注册到 SSE 管理器
sseManager.register(emitter);
return emitter;
}NestJS
typescript
@Sse('connect')
connect(): Observable<MessageEvent> {
return new Observable(subscriber => {
sseService.register(subscriber)
})
}使用场景
字典同步
后端字典变更时,推送通知到所有在线客户端,客户端清除缓存并重新加载。
typescript
// composables/useDictSync.ts
on("dict-change", (data) => {
dictStore.clearCache(data.dictCode);
});在线人数
实时显示当前在线用户数。
typescript
// composables/useOnlineCount.ts
on("online-count", (data) => {
onlineCount.value = data.count;
});断线重连
useSse 内置指数退避重连:
| 重试次数 | 等待时间 |
|---|---|
| 1 | 5s |
| 2 | 10s |
| 3 | 20s |
| 4+ | 120s(上限) |
下一步
- useSse — SSE Composable API
- useDictSync — 字典同步实现
- Spring Boot 实时通信 — 后端实现
