循环依赖Socket.io NodeJS错误

问题描述 投票:0回答:1

我正在构建一个聊天应用程序,我正在尝试利用 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');

根据我的研究,这两个代码似乎相互依赖,但我该如何解决这个问题

node.js socket.io circular-dependency
1个回答
0
投票

正如您所提到的,代码具有循环依赖关系,并且可以修复它,此外,代码尝试使用 Express 应用程序实例实例化 SocketIO 服务器,但是,服务器需要一个 Node.js HTTP 服务器 实例。

当前流量为:

    1. server.js
      构建express应用程序
      PLUS
      需要服务器作为依赖项的套接字;
    1. server.js
      导入
      ./routes/auth.js
      ,再次调用
      server.js
      ,所以
      server.js -> auth.js -> server.js
      ,这会导致无限循环,我们需要删除从
      auth.js
      到第一步的链接;

为了解决这个问题,我们可以使用单例设计模式,因为它确保类/变量只有一个实例,同时提供对此实例的全局访问点。让我们将套接字实例化分离到一个单独的工厂文件中,我们需要实现的是避免循环引用,所以让我们将新的解决方案考虑为:

    1. server.js
      构建 Express 实例
      PLUS
      Node.js HTTP 服务器,并调用 SocketIO Factory 来构建它;
    1. Socket.IO
      工厂构建实例,并用它设置一个单例变量;
    1. 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,因为它是一个非常好的包来帮助您找到它们。

© www.soinside.com 2019 - 2024. All rights reserved.