You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js多路由场景下Socket.io的初始化与使用方法

在MERN应用中多路由使用Socket.io实现实时通知的方案

核心问题分析

你当前的Socket.io初始化代码局限在mongoose.connect的回调函数中,导致io实例的作用域被限制,无法在其他路由模块中访问。要在多路由中使用Socket.io,关键是让io实例全局可访问,并建立用户与Socket连接的映射,以便精准推送通知。

解决方案步骤及示例代码

1. 重构Socket.io与服务器初始化

将服务器创建、Socket.io初始化与数据库连接解耦,把io实例挂载到Express的app对象上,同时维护用户-Socket ID的映射表:

const express = require('express');
const mongoose = require('mongoose');
const http = require('http');
const { Server } = require('socket.io');

const app = express();
// 先创建HTTP服务器,再挂载Socket.io
const server = http.createServer(app);

// 初始化Socket.io并配置CORS
const io = new Server(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"]
  },
});

// 存储用户ID到Socket ID的映射,用于定位用户连接
const userSocketMap = new Map();

// 挂载io和映射表到app对象,方便后续路由访问
app.set('io', io);
app.set('userSocketMap', userSocketMap);

// 处理Socket连接事件
io.on('connection', (socket) => {
  // 前端连接后需发送用户ID完成初始化(比如登录后)
  socket.on('setup', (userId) => {
    userSocketMap.set(userId, socket.id);
    socket.join(userId); // 创建用户专属房间,简化推送逻辑
  });

  // 用户断开连接时清理映射
  socket.on('disconnect', () => {
    for (const [id, socketId] of userSocketMap.entries()) {
      if (socketId === socket.id) {
        userSocketMap.delete(id);
        break;
      }
    }
  });
});

// 数据库连接成功后启动服务器
mongoose.connect(process.env.MongoDb_Url)
  .then(() => {
    server.listen(5000, () => console.log("Server And Database Are Running"));
  })
  .catch((error) => console.log(error.message));

2. 创建Socket中间件注入路由

编写中间件,将io实例和用户映射表注入到请求对象中,让路由可以直接调用:

// middleware/socketMiddleware.js
module.exports = (req, res, next) => {
  req.io = req.app.get('io');
  req.userSocketMap = req.app.get('userSocketMap');
  next();
};

3. 在POST路由中发送实时通知

以通知路由为例,应用中间件后即可在接口中触发Socket推送:

// routes/notifications.js
const express = require('express');
const router = express.Router();
const socketMiddleware = require('../middleware/socketMiddleware');
// 假设你有通知模型
const Notification = require('../models/Notification');

// 给该路由下所有请求注入Socket相关对象
router.use(socketMiddleware);

// 示例:创建并发送通知的POST接口
router.post('/send', async (req, res) => {
  try {
    const { recipientId, title, content } = req.body;

    // 1. 先将通知保存到数据库(可选,根据业务需求)
    const newNotification = new Notification({
      recipient: recipientId,
      title,
      content,
      read: false
    });
    await newNotification.save();

    // 2. 通过用户映射表找到接收者的Socket连接
    const recipientSocketId = req.userSocketMap.get(recipientId);
    if (recipientSocketId) {
      // 方式1:通过Socket ID推送
      req.io.to(recipientSocketId).emit('newNotification', newNotification);
      // 方式2:通过用户房间推送(更简洁)
      // req.io.to(recipientId).emit('newNotification', newNotification);
    }

    res.status(200).json({
      success: true,
      message: '通知已创建并推送',
      notification: newNotification
    });
  } catch (err) {
    res.status(500).json({ success: false, error: err.message });
  }
});

module.exports = router;

4. 前端Socket连接与监听

在React前端中连接Socket.io,并完成用户初始化、监听通知:

// 前端示例(比如App.js)
import { useEffect } from 'react';
import { io } from 'socket.io-client';

function App() {
  useEffect(() => {
    // 连接后端Socket服务
    const socket = io('http://localhost:5000');
    
    // 假设从登录状态中获取用户ID
    const userId = localStorage.getItem('userId');
    if (userId) {
      // 发送用户ID完成Socket初始化
      socket.emit('setup', userId);
    }

    // 监听实时通知
    socket.on('newNotification', (notification) => {
      console.log('收到新通知:', notification);
      // 这里可以做通知弹窗、更新通知列表等操作
    });

    // 组件卸载时断开连接
    return () => {
      socket.disconnect();
    };
  }, []);

  return (
    <div className="App">
      {/* 你的应用内容 */}
    </div>
  );
}

export default App;

关键说明

  • 作用域问题:将io挂载到app对象上,避免了回调函数的作用域限制,让所有路由模块都能访问到实例。
  • 用户定位:通过userSocketMap维护用户与Socket的映射,是实现精准推送的核心,确保通知能发送到目标用户的在线连接。
  • 房间功能:使用socket.join(userId)创建用户专属房间,后续推送时直接通过房间ID发送,比通过Socket ID更简洁可靠。

内容的提问来源于stack exchange,提问作者Jalal Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:46:14