如何使用Telegraf.js正确实现Telegram机器人向频道转发消息
问题描述
我遇到了报错,不清楚如何使用Telegraf.js实现Telegram机器人向频道转发消息。我预期在发送第一条消息后再发送第二条,但实际触发操作后只会转发第一条消息。
- 机器人内的回复内容:

- 频道实际接收到的内容:

我的实现代码如下:
bot.on('message', async (ctx) => { const getFilmId = await kinoInfo(ctx.message.text); const infoFilm = getFilmId.data.data; const id = infoFilm.filmId; const name = infoFilm.nameRu; ctx.reply(name, { reply_markup: { inline_keyboard: [ [{ text: `Watch`, url: 'https://www.instagram.com/' }], [{ text: 'Telegram channel 1', callback_data: 'ONE' }], ], }, }); bot.on('callback_query', (ctx) => { const data = ctx.update.callback_query.data; if (data === 'ONE') { postToChannel(ctx); } }); const postToChannel = (ctx) => { ctx.telegram.sendMessage('@fgdsfsdfsd', name, { parse_mode: 'html', reply_markup: { inline_keyboard: [[{ text: `Watch`, url: 'https://www.instagram.com/' }]], }, }); }; });
问题原因
你代码的核心错误是将callback_query事件监听放在了message事件的回调内部:
- 每次收到用户发来的新消息,都会重复注册一个新的回调查询监听器,旧的监听器不会被销毁
- 每个监听器都会捕获对应
message回调作用域内的name变量,触发按钮时所有历史注册的监听器都会执行,最终会出现始终发送最早的第一条消息的异常。
修复方案
将callback_query事件监听移到全局作用域,需要传递的电影名称可以通过callback_data字段携带,避免闭包捕获导致的变量异常。修正后的代码如下:
// 全局注册回调查询监听 bot.on('callback_query', async (ctx) => { const data = ctx.update.callback_query.data; // 拆分callback_data拿到操作类型和电影名 const [action, filmName] = data.split(':'); if (action === 'post_to_channel') { await ctx.telegram.sendMessage('@fgdsfsdfsd', filmName, { parse_mode: 'html', reply_markup: { inline_keyboard: [[{ text: `Watch`, url: 'https://www.instagram.com/' }]], }, }); // 回应用户的回调查询,避免按钮一直处于加载状态 await ctx.answerCbQuery('已成功转发到频道'); } }); bot.on('message', async (ctx) => { const getFilmId = await kinoInfo(ctx.message.text); const infoFilm = getFilmId.data.data; const name = infoFilm.nameRu; ctx.reply(name, { reply_markup: { inline_keyboard: [ [{ text: `Watch`, url: 'https://www.instagram.com/' }], // 将电影名拼接进callback_data传递给回调监听 [{ text: 'Telegram channel 1', callback_data: `post_to_channel:${name}` }], ], }, }); });
注意事项
callback_data最大长度为64字节,如果电影名过长建议使用会话存储存储用户当前选中的电影信息,避免超出长度限制。- 回调查询触发后必须调用
ctx.answerCbQuery()回应用户,否则客户端的按钮会一直处于转圈加载状态。
内容的提问来源于stack exchange,提问作者Gapanovich
相关产品推荐
相关产品推荐

