Express JS项目不同控制器中调用Socket IO发送消息的实现问题
解决方案
步骤1:将Socket IO实例挂载到Express全局上下文
修改server.js初始化逻辑,把IO实例绑定到Express的app对象上,方便全局调用:
const express = require('express') const http = require('http') const { Server } = require('socket.io') const app = express() const server = http.createServer(app) const io = new Server(server, { // 按需配置跨域等参数 cors: { origin: "*" } }) // 关键步骤:将io实例挂载到app全局属性 app.set('io', io) // 原有连接监听逻辑 io.on('connection', (socket) => { socket.emit('message', 'This is a test message from the server.') }) // 后续挂载路由、启动服务等逻辑保持不变 // app.use('/api', yourRouter) server.listen(3000, () => console.log('服务启动在3000端口'))
步骤2:在控制器中调用Socket IO实例
Express控制器的request对象自带app属性,可以直接获取到挂载的io实例,可根据需求选择广播或者定向发送消息:
const getComments = asyncHandler(async (request, response) => { // 从request对象中获取全局io实例 const io = request.app.get('io') const { liveID, token: accessToken } = request.body var source = new EventSource( `https://streaming-graph.facebook.com/${liveID}/live_comments?access_token=${accessToken}&comment_rate=one_per_two_seconds&fields=from{name,id},message` ) source.onmessage = function (event) { const commentData = JSON.parse(event.data) // 场景1:给所有已连接的客户端广播评论数据 io.emit('new-live-comment', commentData) // 场景2:如果需要定向发给指定用户(比如仅当前请求的发起者) // 需要提前绑定用户ID和socket.id,参考补充说明的逻辑 // const targetSocketId = global.userSocketMap.get(request.user.id) // targetSocketId && io.to(targetSocketId).emit('new-live-comment', commentData) } source.onerror = function (error) { console.log('Error!') console.log(error) } source.onopen = function (event) { console.log(event) } // 按需提前返回响应,无需等待EventSource结束 response.status(200).json({ status: 'ok', msg: '评论流监听已启动' }) })
补充说明(定向发送可选)
如果需要实现用户级别的定向消息发送,可以在Socket连接时存储用户和SocketID的映射关系,修改server.js的connection逻辑即可:
// 单实例部署可以用Map存储,分布式部署可以替换为redis const userSocketMap = new Map() io.on('connection', (socket) => { // 客户端连接时在query参数携带用户ID做身份绑定 const userId = socket.handshake.query.userId if(userId) { userSocketMap.set(userId, socket.id) } socket.emit('message', 'This is a test message from the server.') // 断开连接时删除映射避免内存泄漏 socket.on('disconnect', () => { userId && userSocketMap.delete(userId) }) })
内容的提问来源于stack exchange,提问作者Justin
相关产品推荐
相关产品推荐

