Telegram机器人重复发送图片问题:点击次数对应发送次数
解决Telegram Bot多次点击上传按钮后重复发送图片的问题
问题现象
- 首次点击「Upload Photo」按钮,机器人正常发送1次图片;
- 多次点击该按钮后,后续上传图片时,图片发送次数等于之前点击按钮的总次数(包含历史点击次数)。
原代码
const keyboard = { reply_markup:{ keyboard: [ [{text: 'About Bot'}, {text: 'Upload Photo'}] ] } } bot.onText(/\/start/, async msg => { await bot.sendMessage(h.id(msg), `Choose any`,keyboard) }) bot.on('message', msg => { switch (msg.text){ case 'Upload Photo': uploadPhoto(h.id(msg)) break case 'About Bot': break } }) const uploadPhoto = async (chatId) => { await bot.sendMessage(chatId, 'Send me a photo') bot.on('photo', async (msg) => { const photo = msg.photo[2].file_id await bot.sendPhoto(channelId, photo) await bot.sendMessage(chatId, 'Photo is sent') }) }
问题根源
每次调用uploadPhoto函数时,都会通过bot.on('photo', ...)注册一个全局的photo事件监听器,这些监听器不会自动销毁。多次点击按钮后,就会堆积多个监听器,当用户发送图片时,所有已注册的监听器都会被触发,导致图片重复发送。
解决方案
方案1:使用一次性监听器(最简单)
用bot.once('photo', ...)替代bot.on,once注册的监听器只会触发一次,触发后自动移除,不会产生堆积:
const keyboard = { reply_markup:{ keyboard: [ [{text: 'About Bot'}, {text: 'Upload Photo'}] ] } } bot.onText(/\/start/, async msg => { await bot.sendMessage(h.id(msg), `Choose any`, keyboard) }) bot.on('message', msg => { switch (msg.text){ case 'Upload Photo': uploadPhoto(h.id(msg)) break case 'About Bot': break } }) const uploadPhoto = async (chatId) => { await bot.sendMessage(chatId, 'Send me a photo') // 使用once替代on,监听器触发一次后自动销毁 bot.once('photo', async (msg) => { const photo = msg.photo[2].file_id await bot.sendPhoto(channelId, photo) await bot.sendMessage(chatId, 'Photo is sent') }) }
方案2:手动移除监听器(更精准)
如果需要只响应当前对话用户的图片,可以定义命名监听器函数,触发后手动移除,同时增加对话ID判断:
const keyboard = { reply_markup:{ keyboard: [ [{text: 'About Bot'}, {text: 'Upload Photo'}] ] } } bot.onText(/\/start/, async msg => { await bot.sendMessage(h.id(msg), `Choose any`, keyboard) }) bot.on('message', msg => { switch (msg.text){ case 'Upload Photo': uploadPhoto(h.id(msg)) break case 'About Bot': break } }) const uploadPhoto = async (chatId) => { await bot.sendMessage(chatId, 'Send me a photo') // 定义命名的监听器函数 async function handlePhoto(msg) { // 仅处理当前点击按钮的用户发送的图片 if (h.id(msg) !== chatId) return; const photo = msg.photo[2].file_id await bot.sendPhoto(channelId, photo) await bot.sendMessage(chatId, 'Photo is sent') // 触发后移除监听器 bot.off('photo', handlePhoto) } bot.on('photo', handlePhoto) }
内容的提问来源于stack exchange,提问作者Eliot_Campbell
相关产品推荐
相关产品推荐

