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

Node.js跨模块调用Bot实例方法:如何实现事件通信避免轮询错误?

项目架构
  • index.js -> server.js
  • index.js -> bot.js

问题描述

index.js中同时运行Express服务器实例和Telegram Bot实例,还有定时从外部API拉取数据的脚本。当前端调用server的API接口时,需要调用index.js中已存在的bot实例方法,但不能重新创建bot对象(否则会触发polling error)。有Electron进程间通信经验,想了解非Electron环境下的实现方案,包括合适的npm包或技巧。

代码示例

index.js

// Bot
const bot = require("./bot");

// Admin-panel
const adminPanel = require("./server");

async function start() {
    // 简化后的主脚本
    const data = await axios.get("Some link here")
    if (data.someData == true){
         bot.sendMessage(someId,`Some message`)
    }
}

bot.js

const TelegramBot = require("node-telegram-bot-api");
const bot = new TelegramBot(process.env.BOT_TOKEN, { polling: true });

bot.on("message", (msg) => {
     // 处理消息逻辑
});

bot.on("polling_error", console.log);

module.exports = bot;

server.js

const express = require("express");
const path = require("path");
const app = express();
const fs = require("fs");

app.use(express.json());
app.use(express.static(path.resolve(__dirname, "..", "public")));

app.use("/api/sendMessage", (req, res) => {
    const {message} = req.body;
    // 在这里调用bot.sendMessage(someId, message)
});

app.listen(5000);

module.exports = app;

解决方案

方法1:将bot实例注入Express(最直接)

修改模块结构,让server接收已初始化的bot实例,避免重复创建:

  1. 改造server.js,导出接收bot的函数:
const express = require("express");
const path = require("path");
const fs = require("fs");

module.exports = function(bot) {
    const app = express();

    app.use(express.json());
    app.use(express.static(path.resolve(__dirname, "..", "public")));

    app.use("/api/sendMessage", (req, res) => {
        const {message} = req.body;
        // 直接使用传入的bot实例
        bot.sendMessage(someId, message)
            .then(() => res.status(200).send("消息发送成功"))
            .catch(err => res.status(500).send(err.message));
    });

    app.listen(5000);
    return app;
}
  1. 修改index.js,传入bot实例启动server:
// Bot
const bot = require("./bot");

// Admin-panel - 传入已初始化的bot
const adminPanel = require("./server")(bot);

async function start() {
    const data = await axios.get("Some link here")
    if (data.someData == true){
         bot.sendMessage(someId,`Some message`)
    }
}

方法2:利用Node.js模块缓存(最简单)

Node.js的require默认会缓存模块导出,只要bot.js导出的是已初始化的实例,在server.js中直接require('./bot')就能拿到和index.js中同一个实例:
修改server.js:

const express = require("express");
const path = require("path");
const app = express();
const fs = require("fs");
const bot = require('./bot'); // 这里拿到的是和index.js完全相同的实例

app.use(express.json());
app.use(express.static(path.resolve(__dirname, "..", "public")));

app.use("/api/sendMessage", (req, res) => {
    const {message} = req.body;
    bot.sendMessage(someId, message)
        .then(() => res.status(200).send("消息发送成功"))
        .catch(err => res.status(500).send(err.message));
});

app.listen(5000);

module.exports = app;

这种方式无需额外改造,完全利用Node.js原生特性,不会重复创建bot实例。

方法3:全局变量(应急可用,不推荐)

在index.js中将bot挂载到全局对象:

global.botInstance = require("./bot");

然后在server.js中直接使用global.botInstance.sendMessage(...),但这种方式会污染全局命名空间,大型项目不建议使用。

方法4:进程间通信(IPC,适合进程分离场景)

如果后续需要将bot和server拆分为独立进程,可使用Node.js原生child_process模块实现IPC:

  • 主进程index.js启动server子进程,通过child.send()发送指令
  • 子进程server.js通过process.on('message')接收请求,主进程处理后返回结果
    不过这种方式相对复杂,若当前无需分离进程,前两种方法更高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:47:48