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

求助:Telegram Bot的ReplyKeyboardMarkup多用户点击消息异常

问题描述

当两名用户同时点击ReplyKeyboardMarkup中的按钮时,机器人会将两条消息都发送至同一个聊天窗口(日志显示消息来自同一ID),另一名用户完全收不到消息。同步版Telebot和异步版AsyncTeleBot均存在此问题,但使用InlineKeyboardMarkup时无异常。询问是否需要通过threading库实现多线程,或是pyTelegramBotApi有相关解决功能。

问题原因

你的代码存在严重结构错误:在callback_inline函数的sad分支中,嵌套定义了@bot.message_handler(func=lambda message: True)装饰的函数vpn_problem_page_faq。

  • 每次有用户触发callback_data="sad"的回调时,都会向bot注册一个新的全局消息处理器
  • 这个处理器内部硬编码使用了call.message.chat.id,也就是第一个触发该回调的用户的聊天ID
  • 后续所有用户发送的"Click here"消息,都会被这个处理器捕获,并将回复发送到第一个用户的窗口
  • InlineKeyboardMarkup使用的是callback_query,每个回调都携带当前用户的聊天ID,因此不会出现混淆问题
解决方案

不要在处理器内部嵌套注册新的处理器,应通过用户状态管理区分不同用户的交互流程。以下是修正后的代码:

import telebot
from telebot.async_telebot import AsyncTeleBot
from telebot.async_telebot import types
import asyncio
import logging

logger = telebot.logger
telebot.logger.setLevel(logging.DEBUG)
bot = AsyncTeleBot("YOUR_TOKEN_HERE")

# 用字典存储用户当前状态,key为用户ID,value为状态标识
user_states = {}

def start_page_markup():
    reply_markup = types.InlineKeyboardMarkup(row_width=1)
    faces_choose = types.InlineKeyboardButton("Choose your face", callback_data="face_choose")
    reply_markup.add(faces_choose)
    return reply_markup

def faces_markup():
    reply_markup = types.InlineKeyboardMarkup(row_width=1)
    one_button = types.InlineKeyboardButton(text="☹️", callback_data="sad")
    two_button = types.InlineKeyboardButton(text="🙂", callback_data="smile")
    reply_markup.add(one_button, two_button)
    return reply_markup

def chear_up_sad_markup():
    reply_markup = types.ReplyKeyboardMarkup(resize_keyboard=True, row_width=1)
    q1 = types.KeyboardButton("Click here")
    reply_markup.add(q1)
    return reply_markup

@bot.message_handler(commands=["start"])
async def start(message):
    # 用户启动时重置状态
    user_states[message.from_user.id] = "start"
    await bot.send_message(message.chat.id, "Hello my friend", reply_markup=start_page_markup())

@bot.callback_query_handler(func=lambda call: True)
async def callback_inline(call):
    if call.message:
        user_id = call.from_user.id
        if call.data == "face_choose":
            user_states[user_id] = "face_choose"
            await bot.send_message(call.message.chat.id, "I'm waiting....", reply_markup=faces_markup())
        elif call.data == "sad":
            user_states[user_id] = "sad_state"
            await bot.send_message(call.message.chat.id, 'Why are u sad ????', reply_markup=chear_up_sad_markup())
        elif call.data == "smile":
            user_states[user_id] = "smile_state"
            await bot.send_message(call.message.chat.id, 'You are cute, smile more !!!')

# 全局消息处理器,根据用户状态处理不同逻辑
@bot.message_handler(func=lambda message: True)
async def handle_messages(message):
    user_id = message.from_user.id
    current_state = user_states.get(user_id, "start")
    
    if current_state == "sad_state" and message.text == "Click here":
        await bot.send_message(chat_id=message.chat.id, text="Nooooooo..... Don't be sad !!!")
        await bot.send_message(chat_id=message.chat.id, text="You are smart, cute, strong badass !!!!!")
        # 处理完后重置状态
        user_states[user_id] = "start"

if __name__ == "__main__":
    asyncio.run(bot.polling())
补充说明
  • 不需要额外使用threading库,pyTelegramBotAPI(无论同步还是异步版本)本身已处理并发请求的路由
  • 核心问题是错误的处理器注册方式,而非并发机制缺陷
  • 状态管理是多用户Telegram Bot开发的基础,除字典外,还可使用数据库(如SQLite、Redis)存储更复杂的用户状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 11:37:17