服务器端WebSocket配置求助:nftController中wss变量未定义
问题:nftController中wss变量始终为undefined
配置服务器端WebSocket时,nftController.js中从server.js导入的wss变量始终显示undefined,已确认导入路径和导出逻辑无误,相关代码如下:
server.js
const dotenv = require("dotenv"); const mongoose = require("mongoose"); const app = require("./app"); const WebSocket = require('ws'); const http = require("http"); const server = http.createServer(app); const wss = new WebSocket.Server({ server }); process.on("uncaughtException", err=>{ console.log("uncaughtException Shutting down Application"); console.log(err.name, err.message); process.exit(1); }); dotenv.config({ path: "./config.env" }); const DB = "mongodb+srv://rameez:<PASSWORD>@cluster0.ogku096.mongodb.net/NFTMarketplace?retryWrites=true&w=majority" mongoose .connect(DB, { useCreateIndex: true, useFindAndModify: false, useNewUrlParser: true, useUnifiedTopology: false, }) .then((con) => { console.log("DB Connection Successfully"); }) console.log(process.env.NODE_ENV); app.get('/', (req, res) => { res.send('Hello, world!'); }); wss.on('connection', (ws) => { console.log('New WebSocket connection'); }); const port = process.env.PORT || 4000; server.listen(port, () => { console.log(`App running on port ${port}....`); }); process.on("unhandledRejection", (err) => { console.log("unhandledRejection Shutting down Application"); console.log(err.name, err.message); server.close(() => { process.exit(1); }); }); module.exports = { wss };
nftController.js
const { wss } = require("../server"); const NFT = require("./../models/nftModel"); const APIFeatures = require("./../Utils/apiFeatures"); const catchAsync = require("../Utils/catchAsync"); const AppError = require("../Utils/appError"); console.log("wss", wss); // Update top 5 NFTs data whenever there is new data exports.aliasTopNFTs = catchAsync(async (req, res, next) => { req.query.limit = "5"; req.query.sort = "-price"; req.query.fields = "name,price,seller,image,createAt"; const features = new APIFeatures(NFT.find(), req.query) .filter() .sort() .limitFields() .pagination(); const nfts = await features.query; req.query.nfts = nfts; next(); }); const sendUpdatedData = (data) => { wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'UPDATE_DATA', data: data })); } }); } exports.getAllNfts = catchAsync(async (req, res) => { const features = new APIFeatures(NFT.find(), req.query) .filter() .sort() .limitFields() .pagination(); const nfts = await features.query; sendUpdatedData(nfts); console.log("WSSdata", nfts); //SEND QUERY res.status(200).json({ status: "success", results: nfts.length, data: { nfts, }, }); });
解决方案
问题根源
这是模块循环加载导致的初始化顺序问题:server.js中引入了./app,而app.js必然会引入nftController.js(作为路由控制器)。当nftController.js在顶部导入server.js时,server.js的代码还未执行到module.exports = { wss }这一行,此时wss变量尚未被赋值,因此得到undefined。
方法1:拆分WebSocket模块(推荐)
将WebSocket相关逻辑单独抽离成模块,避免循环依赖,同时保证wss实例初始化完成后再被调用:
- 创建
wsServer.js文件:
const WebSocket = require('ws'); let wssInstance = null; // 初始化WebSocket服务器 function initWebSocketServer(server) { wssInstance = new WebSocket.Server({ server }); wssInstance.on('connection', (ws) => { console.log('New WebSocket connection'); }); return wssInstance; } // 获取已初始化的wss实例 function getWebSocketServer() { return wssInstance; } module.exports = { initWebSocketServer, getWebSocketServer };
- 修改
server.js,使用新模块初始化wss:
const dotenv = require("dotenv"); const mongoose = require("mongoose"); const app = require("./app"); const http = require("http"); const { initWebSocketServer } = require('./wsServer'); // 导入WebSocket模块 const server = http.createServer(app); // 初始化WebSocket服务器 initWebSocketServer(server); // 原有其余代码保持不变... // 移除原有的module.exports = { wss };
- 修改
nftController.js,从新模块获取wss实例:
const { getWebSocketServer } = require("../wsServer"); // 替换导入源 const NFT = require("./../models/nftModel"); const APIFeatures = require("./../Utils/apiFeatures"); const catchAsync = require("../Utils/catchAsync"); const AppError = require("../Utils/appError"); const WebSocket = require('ws'); // 补上WebSocket导入,解决OPEN常量问题 const sendUpdatedData = (data) => { const wss = getWebSocketServer(); if (!wss) return; // 防止服务器未完成初始化时调用 wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'UPDATE_DATA', data: data })); } }); } // 原有其余代码保持不变...
方法2:延迟导入(临时方案)
如果不想拆分模块,可以在需要使用wss的函数内部动态导入server.js,此时server已完成初始化:
修改nftController.js中的sendUpdatedData函数:
const sendUpdatedData = (data) => { const { wss } = require("../server"); // 在函数内部导入 const WebSocket = require('ws'); // 补上WebSocket导入 if (!wss) return; wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'UPDATE_DATA', data: data })); } }); }
该方法虽然简单,但不够优雅,不利于代码维护,仅作为临时解决手段。
内容的提问来源于stack exchange,提问作者The Day Galpu Club
相关产品推荐
相关产品推荐

