如何使用Server-Sent Events向指定用户ID发送消息
Server-Sent Events 定向推送能力解答
首先给出明确结论:SSE 并非只能实现广播推送,完全支持根据用户ID向特定用户发送消息,推送模式完全由服务端的业务实现逻辑决定,和SSE协议本身无关。
- SSE 本质是客户端和服务端单独建立的单向HTTP长连接,每一条连接都是独立的。服务端可以在连接建立阶段完成用户身份校验,解析得到用户ID后,将当前连接的响应上下文和用户ID做绑定存储即可。
- 定向推送的实现逻辑非常直接:需要给指定用户发消息时,只需要从绑定关系中查询到该用户关联的所有SSE连接,往对应连接的响应流中写入符合SSE格式的消息即可,不会影响其他用户的连接。
- 广播是SSE的可选使用场景而非强制模式:只有当业务需要给所有在线用户推送相同消息(比如全站公告)时,才需要遍历所有在线SSE连接做批量推送,这属于业务层的逻辑选择,不是SSE的固有特性。
简单实现示例(Node.js)
// 存储用户ID与对应SSE连接的映射关系 const userConnectionMap = new Map() // SSE连接建立接口 app.get('/sse/connect', (req, res) => { // 从请求鉴权信息中解析当前登录用户ID,需提前完成token校验逻辑 const curUserId = req.auth.userId // 写入SSE协议要求的响应头 res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }) // 绑定用户ID与当前连接 if(!userConnectionMap.has(curUserId)) { userConnectionMap.set(curUserId, []) } userConnectionMap.get(curUserId).push(res) // 连接断开时清理无效连接 req.on('close', () => { const validConnections = userConnectionMap.get(curUserId).filter(conn => conn !== res) validConnections.length ? userConnectionMap.set(curUserId, validConnections) : userConnectionMap.delete(curUserId) }) }) // 定向给指定用户发消息的公用方法 function pushToSpecificUser(userId, msgContent) { const targetConnections = userConnectionMap.get(userId) if(!targetConnections) return // 按SSE协议格式写入消息 targetConnections.forEach(conn => conn.write(`data: ${JSON.stringify(msgContent)}\n\n`)) }
如果是多实例集群部署的场景,只需要引入发布订阅组件(比如Redis Pub/Sub)做跨实例的消息通知即可,同样不需要修改SSE本身的交互逻辑。
内容的提问来源于stack exchange,提问作者user15361861
相关产品推荐
相关产品推荐

