Telegraf.js开发Telegram Bot:Wizard Scene需注释bot.on('text')才能工作
Telegraf.js全局text处理器与Wizard Scene冲突解决方案
问题根源
Telegraf的中间件按注册顺序执行,全局bot.on('text')会拦截所有文本消息,且你的代码里没有调用next()传递控制权,导致Wizard Scene的步骤处理器永远无法接收到消息,自然无法正常运行。
解决方案
方案1:全局处理器中判断场景状态,按需传递控制权
修改全局text处理器,当用户处于Wizard Scene中时,调用next()把消息交给场景处理器;否则执行全局逻辑。
bot.on('text', async (ctx, next) => { try { // 检查当前是否有运行中的场景 if (!ctx.scene.current) { switch (ctx.message.text) { // 你的原有业务逻辑 case '/start': await ctx.reply('全局Start响应'); break; default: await ctx.reply('全局默认文本响应'); break; } } else { // 处于场景中,转交控制权给场景处理器 await next(); } } catch (e) { console.error(e); // 即使出错,也建议调用next避免阻塞后续中间件 await next(); } })
方案2:调整中间件注册顺序,让场景优先处理
把Wizard Scene的中间件注册放在全局text处理器之前,这样场景的处理器会先拦截文本消息,只有场景未处理的消息才会流到全局处理器。
// 先注册会话和场景中间件 bot.use(session()); const myWizard = new WizardScene('my-wizard', stepHandler, /* 其他步骤 */); bot.use(myWizard.middleware()); // 再注册全局text处理器 bot.on('text', async (ctx) => { try { switch (ctx.message.text) { // 你的原有逻辑 } } catch (e) { console.error(e); } })
方案3:用bot.hears()替代全局bot.on('text')(推荐)
放弃拦截所有文本的全局处理器,改用bot.hears()针对特定文本/命令单独处理,从根源上避免冲突,代码也更清晰。
// 替代原来的switch逻辑 bot.hears('/start', async (ctx) => { // 处理/start命令 await ctx.reply('全局Start响应'); }); bot.hears('帮助', async (ctx) => { // 处理"帮助"文本 await ctx.reply('全局帮助内容'); }); // 其他需要监听的特定文本
注意事项
- 所有Telegraf中间件如果需要后续逻辑执行,必须调用
next(); - 场景运行时,
ctx.scene.current会返回当前场景的ID,可用于判断用户是否在场景中; - 推荐优先使用方案3,既避免冲突,又符合Telegraf的最佳实践。
内容的提问来源于stack exchange,提问作者shmeqez
相关产品推荐
相关产品推荐

