如何在Express 4(生成器创建)路由中使用Socket.io?
嘿,这个问题我之前刚折腾过,Express 4生成器的结构确实会让Socket.io的对象传递有点绕,不过有几种很实用的方法,我给你一步步拆解清楚:
在Express 4路由中使用Socket.io的实现方案
首先得先把Socket.io和Express的服务器绑定起来,因为Express 4生成器默认把服务器创建逻辑放在了bin/www里,所以第一步从这里入手:
步骤1:初始化Socket.io并关联到Express服务器
打开bin/www文件,找到创建server的代码,修改成这样:
var app = require('../app'); var http = require('http'); const { Server } = require('socket.io'); // 引入Socket.io var server = http.createServer(app); // 初始化Socket.io并绑定到当前server const io = new Server(server); // 把io对象挂载到Express的app实例上,方便后续全局获取 app.set('io', io); // 可选:处理Socket.io的基础连接事件 io.on('connection', (socket) => { console.log('有用户连接到Socket.io了'); socket.on('disconnect', () => { console.log('用户断开了Socket.io连接'); }); }); // 剩下的原有代码保持不变...
现在io对象已经和服务器绑定,并且挂载到了app实例上,接下来看怎么在路由里调用它。
方法1:从req.app中直接获取io对象
这是最省心的方法,不用改路由的引入逻辑,直接在路由里拿:
比如在routes/index.js里:
var express = require('express'); var router = express.Router(); router.get('/broadcast', function(req, res, next) { // 从app实例中取出之前挂载的io对象 const io = req.app.get('io'); // 给所有连接的客户端广播消息 io.emit('server-notice', '这条消息是从Express路由发出来的!'); // 如果要给特定客户端发消息,得提前保存socket实例(比如用用户ID做映射) // 示例:io.to(targetSocketId).emit('private-chat', '专属消息'); res.send('Socket.io消息已发送'); }); module.exports = router;
方法2:把io作为参数传递给路由模块
这种方法更模块化,适合大型项目的路由拆分:
首先修改app.js,在引入路由的时候把io传进去:
var createError = require('http-errors'); var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var logger = require('morgan'); var app = express(); // 先获取之前挂载到app上的io对象 const io = app.get('io'); // 把io作为参数传给路由模块 var indexRouter = require('./routes/index')(io); var usersRouter = require('./routes/users')(io); // ... 中间件配置保持不变 ... app.use('/', indexRouter); app.use('/users', usersRouter); // ... 错误处理代码保持不变 ...
然后修改路由文件routes/index.js,改成接收io参数的函数:
var express = require('express'); // 改为导出一个接收io参数的函数 module.exports = (io) => { var router = express.Router(); router.get('/broadcast', function(req, res, next) { // 直接使用传入的io对象发送消息 io.emit('server-notice', '这条消息来自带参数的路由模块!'); res.send('消息已通过Socket.io发送'); }); return router; };
方法3:用中间件把io附加到req对象上
这种方法可以让所有路由都直接通过req.io访问,不用每次手动获取:
在app.js里添加一个全局中间件(放在路由引入前):
// 在其他中间件之后、路由引入之前添加 app.use((req, res, next) => { // 把io挂载到req对象上 req.io = req.app.get('io'); next(); }); // 然后正常引入路由即可 var indexRouter = require('./routes/index'); var usersRouter = require('./routes/users');
之后在路由里就能直接用了:
router.get('/broadcast', function(req, res, next) { req.io.emit('server-notice', '这条消息来自req.io!'); res.send('消息已发送'); });
小提示
如果需要给特定用户发消息,你得在io.on('connection')事件里把每个客户端的socket实例保存起来(比如用一个对象存储用户ID和socket的映射),之后在路由里通过io.to(targetSocketId)来发送专属消息。
内容的提问来源于stack exchange,提问作者Rasool_sof
相关产品推荐
相关产品推荐

