Node.js开发Telegram Bot遭遇重复响应循环问题求助
问题描述
我用Node.js开发了一个Telegram Bot,它能根据用户输入发起电话呼叫。第一次运行正常,但多次操作后会陷入奇怪的循环——每次输入内容,消息都会多发送一次,就像代码没跳出switch语句,一直在监听数字输入。
原代码
require("dotenv").config(); const axios = require("axios"); const express = require("express"); const port = 5000; const app = express(); const Voice = require("@signalwire/realtime-api").Voice; const { TOKEN, SERVER_URL } = process.env; const URI = `/webhook/${TOKEN}`; const TelegramBot = require("node-telegram-bot-api"); const { reset, restart } = require("nodemon"); const nodemon = require("nodemon"); var chatId; // replace the value below with the Telegram token you receive from @BotFather const token = "<token>"; // Create a bot that uses 'polling' to fetch new updates const bot = new TelegramBot(token, { polling: true }); bot.on("message", (msg) => { chatId = msg.chat.id; if (msg.text == "/call") { chooseBank(); } if (msg.text == "/restart") { recover(); } }); //GIVE OPTION FOR THE CLIENT function chooseBank() { bot.sendMessage( chatId, "CHOOSE THE BANK: \n\n1 RBC\n2 CIBC\n3 SCOTIA\n4 BMO\n5 NATIONAL\n6 TD\n7 PC-FINANCIAL\n8 DESJARDINS" ); bot.on("message", (msg) => { switch (msg.text) { case "1": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); break; case "2": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); break; case "3": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); break; case "4": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); break; case "5": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); break; case "6": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); break; case "7": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); break; case "8": bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); } }); } function recover(){ chooseBank() } app.listen(port, () => { console.log(`Server started on port ${port}`); });
问题根源
每次调用chooseBank()时,都会给bot绑定一个新的message事件监听器。第一次调用添加1个监听器,第二次调用再添加1个,以此类推。后续用户发送的每条消息都会被所有已绑定的监听器处理,导致响应次数随操作次数递增。
解决方案
采用状态机模式跟踪用户的操作步骤,所有消息逻辑都在全局的message监听器中处理,避免重复绑定事件。
修正后代码
require("dotenv").config(); const axios = require("axios"); const express = require("express"); const port = 5000; const app = express(); const Voice = require("@signalwire/realtime-api").Voice; const { TOKEN, SERVER_URL } = process.env; const URI = `/webhook/${TOKEN}`; const TelegramBot = require("node-telegram-bot-api"); const nodemon = require("nodemon"); // 记录每个用户的当前操作状态,key为chatId,value为步骤标识 const userStates = {}; // replace the value below with the Telegram token you receive from @BotFather const token = "<token>"; // Create a bot that uses 'polling' to fetch new updates const bot = new TelegramBot(token, { polling: true }); bot.on("message", (msg) => { const chatId = msg.chat.id; const text = msg.text.trim(); // 处理命令 if (text === "/call") { userStates[chatId] = "choosing_bank"; bot.sendMessage( chatId, "CHOOSE THE BANK: \n\n1 RBC\n2 CIBC\n3 SCOTIA\n4 BMO\n5 NATIONAL\n6 TD\n7 PC-FINANCIAL\n8 DESJARDINS" ); return; } if (text === "/restart") { userStates[chatId] = "choosing_bank"; bot.sendMessage( chatId, "CHOOSE THE BANK: \n\n1 RBC\n2 CIBC\n3 SCOTIA\n4 BMO\n5 NATIONAL\n6 TD\n7 PC-FINANCIAL\n8 DESJARDINS" ); return; } // 根据用户当前状态处理消息 const currentState = userStates[chatId]; if (!currentState) return; switch (currentState) { case "choosing_bank": // 验证输入是否为1-8的数字 if (["1", "2", "3", "4", "5", "6", "7", "8"].includes(text)) { userStates[chatId] = "entering_number"; bot.sendMessage( chatId, "ENTER THE CLIENTS NUMBER:\n\nEX: (+15142220000)" ); } else { bot.sendMessage(chatId, "请输入1-8之间的数字选择银行"); } break; case "entering_number": // 此处可添加号码格式验证逻辑,随后发起呼叫 bot.sendMessage(chatId, `已收到号码:${text},即将发起呼叫`); // 完成操作后重置用户状态 delete userStates[chatId]; break; } }); app.listen(port, () => { console.log(`Server started on port ${port}`); });
方案说明
- 使用
userStates对象跟踪每个用户的当前操作步骤(如选择银行、输入号码),确保不同用户的操作互不干扰。 - 所有消息逻辑集中在全局
message监听器中,避免重复绑定事件导致的多次响应问题。 - 操作完成后主动重置用户状态,保证流程可以重新开始。
内容的提问来源于stack exchange,提问作者Steven Yee
相关产品推荐
相关产品推荐

