如何使用Express与Socket.IO通过REST API发送消息
REST API推送消息至Socket.io房间的解决方案
需求场景
开发Node.js聊天应用,支持通过GET请求http://localhost:3000/sendMessage?message=hello&roomId=123,向指定房间内已连接Socket.io的客户端推送消息(如用户C通过API给同房间的A、B发消息)。
原代码问题分析
原代码存在以下关键问题:
- Express路由被注册在
io.on("connection")回调内,每次有Socket客户端连接都会重复注册路由,引发请求处理异常 - GET请求的参数存储在
req.query中,原代码错误使用req.body.content获取消息内容 - 固定使用
"devices-in-this-room"作为房间标识,未使用请求传入的动态roomId - 无参数校验和错误处理,响应逻辑不严谨
修正后的完整代码
import express from "express"; import { createServer } from "http"; import { Server } from "socket.io"; const app = express(); const httpServer = createServer(app); const io = new Server(httpServer, { // 按需配置CORS,生产环境建议指定具体域名 cors: { origin: "*", methods: ["GET"] } }); // 独立注册Express路由,避免重复注册 app.get("/sendMessage", function (req, res) { const { message, roomId } = req.query; // 校验必填参数 if (!message || !roomId) { return res.status(400).send("缺少必要参数:message和roomId"); } try { // 向指定房间推送消息,附带元数据便于客户端处理 io.to(roomId).emit("message", { sender: "API", content: message, roomId, timestamp: new Date().toISOString() }); res.status(200).send("消息已推送至目标房间"); } catch (err) { console.error("推送失败:", err); res.status(500).send("消息推送失败"); } }); // Socket客户端连接与房间处理逻辑 io.on("connection", (socket) => { // 监听客户端加入房间的事件(需客户端主动触发) socket.on("joinRoom", (roomId) => { socket.join(roomId); console.log(`客户端 ${socket.id} 加入房间 ${roomId}`); }); socket.on("disconnect", () => { console.log(`客户端 ${socket.id} 断开连接`); }); }); httpServer.listen(3000, () => { console.log("服务运行在 http://localhost:3000"); });
关键修正说明
- 路由独立注册:将
/sendMessage路由移至Socket连接事件外,确保仅注册一次,避免重复路由冲突 - 正确获取参数:通过
req.query获取GET请求的message和roomId参数 - 参数校验与错误处理:校验必填参数,针对不同场景返回对应HTTP状态码和提示信息
- 动态房间推送:使用请求传入的
roomId作为目标房间标识,实现精准推送 - 客户端房间逻辑:补充客户端加入房间的监听逻辑,实际业务中客户端需发送
joinRoom事件并携带房间ID完成加入
内容的提问来源于stack exchange,提问作者Jerry Seigle
相关产品推荐
相关产品推荐

