后台系统里最容易被低估的功能,往往是“通知”。审批流走到哪一步、任务是否完成、用户是否在线、导入是否失败——这些信息如果只能靠刷新页面拿到,体验会很笨重。Wiki-Framework 1.2.0 新增的 wiki-sse 模块,把 Server-Sent Events 作为框架内置能力补上,让服务端单向推送不必一上来就引入 WebSocket。
为什么是 SSE,而不是继续轮询
轮询当然能做:前端每 3 秒请求一次 /notifications,后端查库再返回。但它的问题也很明显:
- 没有消息时也在请求,浪费连接和服务端资源。
- 轮询间隔短,压力大;间隔长,实时性差。
- 每个业务都自己写一套定时器、取消逻辑和错误重试,前端代码容易散。
WebSocket 的能力更完整,适合双向通信、聊天室、协同编辑、实时游戏这类场景。但很多后台需求其实只需要“服务端告诉浏览器发生了什么”。这时 SSE 刚好卡在中间:
- 基于普通 HTTP,部署和排查成本更低。
- 浏览器原生支持
EventSource。 - 连接断开后浏览器可以自动重连。
- 适合通知、进度、状态变更等服务端单向推送。
wiki-sse 的价值就在这里:把这类轻量实时能力纳入 Wiki-Framework,而不是让每个项目重复造一遍。
wiki-sse 适合放在哪些业务里
可以把 SSE 理解成“页面打开后一条持续不断的 HTTP 响应”。服务端不一次性结束响应,而是在有事件时写入类似这样的数据:
event: approval-progress
data: {"id":"A-1001","status":"approved"}
这类模型特别适合后台系统中的几类需求:
- 审批进度:流程节点变化后推送给当前申请人或管理员。
- 站内通知:新任务、新评论、异常告警即时出现在页面角标。
- 导入/导出进度:长任务不需要前端一直查进度接口。
- 在线状态:用户登录、离线、心跳状态变化由服务端广播。
边界也要说清楚:SSE 是单向推送。客户端要发消息,仍然走普通 HTTP API;如果你需要客户端和服务端高频双向通信,WebSocket 仍然更合适。
可以这样实践:前端用 EventSource 接收通知
下面是一个可直接改造到后台页面里的前端示例。假设后端提供了 /api/sse/notifications 端点,并按 SSE 协议返回事件流。
<!doctype html>
<html lang="zh-CN">
<body>
<h1>实时通知</h1>
<ul id="messages"></ul>
<script>
const list = document.querySelector('#messages');
const source = new EventSource('/api/sse/notifications');
source.addEventListener('open', () => {
console.log('SSE connected');
});
source.addEventListener('notification', (event) => {
const payload = JSON.parse(event.data);
const item = document.createElement('li');
item.textContent = `${payload.time} - ${payload.message}`;
list.prepend(item);
});
source.addEventListener('error', () => {
console.warn('SSE disconnected, browser will retry automatically');
});
window.addEventListener('beforeunload', () => {
source.close();
});
</script>
</body>
</html>
要改的地方很少:
- 把
/api/sse/notifications换成你的wiki-sse服务端地址。 - 把事件名
notification换成后端实际发送的事件名。 - 按业务结构解析
event.data。
服务端事件长什么样
即使框架封装了发送细节,理解 SSE 的线格式仍然有帮助。一个最小响应通常长这样:
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
event: notification
data: {"message":"审批单 A-1001 已通过","time":"2025-01-18 10:30:00"}
关键点是:
Content-Type必须是text/event-stream。- 每条消息用空行分隔。
event是事件名,前端用addEventListener监听。data是字符串,通常放 JSON。
如果项目经过 Nginx 代理,还要注意关闭缓冲,否则服务端已经推了,浏览器却迟迟收不到。可以这样配置一个 SSE 路径:
location /api/sse/ {
proxy_pass http://wiki_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 1h;
}
这段配置可以按你的网关域名、后端 upstream 名称修改后使用。
落地时别忽略这些细节
引入 wiki-sse 时,建议把它当成基础设施能力,而不是随手塞进某个业务接口:
- 连接管理:用户关闭页面、切换账号、Token 过期时,要及时释放服务端连接。
- 权限隔离:通知只能推给有权限的人,不能因为广播方便就跨租户、跨部门泄露数据。
- 心跳机制:长连接经过代理、负载均衡时可能被断开,定期发送心跳能减少“假在线”。
- 重连补偿:SSE 会自动重连,但断线期间的关键事件最好能通过通知列表或进度查询接口补回来。
- 容量评估:每个打开页面都是一条连接,管理员大屏、运营后台、移动端同时在线时要估算连接数。
采用建议
如果你的 Wiki-Framework 项目已经有通知、审批进度、在线状态这类需求,wiki-sse 很适合优先接入。它比轮询更省,比 WebSocket 更轻,和后台系统的“服务端单向提醒”模型也更贴合。
一个稳妥的改造路径是:先把通知中心或任务进度这种低风险场景接入 SSE;保留原来的查询接口作为断线补偿;确认代理、鉴权和连接释放都稳定后,再扩展到更多实时模块。