我正在构建一个聊天应用程序,我正在尝试利用 socket.io 来处理实时消息。但是我在后端构建代码的方式有一个 server.js 和一个controller/authController.js,它们处理前端路由中调用的所有 API 函数,所以就像我到处看到的那样,人们使用套接字。 io 在服务器中,但我想在 authController.js 中使用它以及其他功能,如登录、注册、sendMessage,.....但我遇到了下面的错误消息:
(node:1904) Warning: Accessing non-existent property 'io' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
当我运行命令时,我得到这个:
$ node --trace-warnings ...
node:internal/modules/cjs/loader:1078
throw err;
^
Error: Cannot find module 'C:\Users\flex zone\Desktop\Mean app v1\backend\...'
←[90m at Module._resolveFilename (node:internal/modules/cjs/loader:1075:15)←[39m
←[90m at Module._load (node:internal/modules/cjs/loader:920:27)←[39m
←[90m at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)←[39m
←[90m at node:internal/main/run_main_module:23:47←[39m {
code: ←[32m'MODULE_NOT_FOUND'←[39m,
requireStack: []
}
Node.js v18.16.0
这是我做的server.js:
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
require('./config/db').connectDB()
const authRoutes = require('./routes/auth');
const { Server } = require('socket.io')
const PORT = process.env.PORT || 3000;
const app = express();
app.use(bodyParser.json());
app.use(cors());
app.use('/api', authRoutes)
const server = app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
const io = new Server(server)
module.exports = {
io,
}
这是 authController.js,我导入 io 的部分:
const { io } = require('../socket.io.js');
根据我的研究,这两个代码似乎相互依赖,但我该如何解决这个问题
正如您所提到的,代码具有循环依赖关系,并且可以修复它,此外,代码尝试使用 Express 应用程序实例实例化 SocketIO 服务器,但是,服务器需要一个 Node.js HTTP 服务器 实例。
当前流量为:
server.js
构建express应用程序PLUS
需要服务器作为依赖项的套接字;server.js
导入./routes/auth.js
,再次调用server.js
,所以server.js -> auth.js -> server.js
,这会导致无限循环,我们需要删除从auth.js
到第一步的链接;为了解决这个问题,我们可以使用单例设计模式,因为它确保类/变量只有一个实例,同时提供对此实例的全局访问点。让我们将套接字实例化分离到一个单独的工厂文件中,我们需要实现的是避免循环引用,所以让我们将新的解决方案考虑为:
server.js
构建 Express 实例 PLUS
Node.js HTTP 服务器,并调用 SocketIO Factory 来构建它;Socket.IO
工厂构建实例,并用它设置一个单例变量;auth.js
现在引用singleton
内部的socket-factory.js
变量,而不是server.js
,所以新的流程是:
server.js -> socket-factory.js
server.js -> auth.js
auth.js -> socket-factory.js
socket-factory.js
;注意:下面的代码使用 ES6 模块,因为它们更现代:
socket-factory.js
:
import { Server } from 'socket.io';
/**
* @type {Server}
*/
export let socketIOSingleton = null;
export function socketIOFactory(serverInstance) {
socketIOSingleton = new Server(serverInstance)
}
server.js
:
import authRoute from './routes/auth.js';
import express from 'express';
import http from 'http';
import { socketIOFactory, socketIOSingleton } from './socket.js';
const PORT = process.env.PORT || 8000;
const app = express();
const server = http.createServer(app);
app.get('/api/auth', authRoute)
socketIOFactory(server)
socketIOSingleton.on("connection", (socket) => {
console.warn("socket connected")
});
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
auth.js
:
import { socketIOSingleton } from "../socket.js";
export default async function handler(req, res) {
// broadcast a message to all connected clients
socketIOSingleton.emit("message", "Hello everyone!");
return res.status(200).json({ message: 'Hello there!' });
}
此外,如果您发现很难找到循环依赖项的位置,请检查Madge,因为它是一个非常好的包来帮助您找到它们。