多人使用Telegram Bot触发400空消息文本错误的问题求助
问题根因
多用户场景崩溃+400 Bad Request: message text is empty报错由四个代码逻辑缺陷直接导致:
- 协议文本文件句柄全局初始化后未重置:全局作用域打开的
txt文件对象,第一次被/start指令调用txt.read()后,文件指针会移动到内容末尾,后续所有用户触发/start时读取到的都是空字符串,向Telegram API发送空文本就会触发400错误。 - 未做非文本消息拦截:如果用户在交互过程中发送贴纸、图片、语音等非文本内容,
message.text会返回None,直接用这个值作为消息内容发送就会触发空消息错误。 - 注册流程存在并发安全问题:手动循环查找表格空行生成userId的逻辑在多用户同时提交时会生成重复ID,嵌套的下一步回调未做用户隔离,高并发下会出现消息路由错乱。
- TeleBot默认未开启多线程模式,串行处理消息时容易出现请求阻塞、回调覆盖问题。
修复步骤
1. 修复协议文本读取逻辑
删除全局打开文件的写法,程序启动时一次性把协议内容读取到内存字符串中,避免文件指针偏移问题:
# 替换原全局txt = open(...)的写法 with open("C:/Users/nmash/Desktop/Cloud/terms_of_the_agreement.txt", encoding="utf-8") as f: terms_text = f.read()
后续/start逻辑中直接传入terms_text发送即可,不需要重复调用read()。
2. 初始化Bot时开启多线程支持
修改TeleBot初始化参数,支持多用户并发处理:
self.bot = telebot.TeleBot(token, threaded=True)
3. 增加非文本消息拦截
在所有文本处理逻辑前增加message.text非空判断,非文本内容直接提示用户发送文字,避免空值传入发送接口:
@self.bot.message_handler(content_types=['text', 'sticker', 'photo', 'voice', 'document']) def message_worker(message): if not message.text: self.bot.send_message(message.from_user.id, "Пожалуйста, отправляйте текстовые сообщения для работы с ботом") return # 后续保留原/start、同意协议的判断逻辑即可
4. 修复注册流程的并发问题
删除手动循环查找表格空行的逻辑,gspread自带的append_row方法会自动定位到最后一个空行写入,同时从写入返回结果中解析实际行号作为userId,避免并发下ID重复;在接收姓名输入的回调中也增加非空判断,输入不符合要求时重新注册下一步回调要求用户重输:
def registration(self, message): def ask_name(message): sent = self.bot.send_message(message.from_user.id, 'Введите своё имя:') self.bot.register_next_step_handler(sent, save_name) def save_name(message): if not message.text: self.bot.send_message(message.from_user.id, "Имя должно быть текстом, попробуйте снова:") self.bot.register_next_step_handler(message, save_name) return name = message.text.strip() worksheet = sh.sheet1 append_res = worksheet.append_row([name]) # 解析写入结果中的行号作为用户ID user_id = int(append_res['updates']['updatedRange'].split('A')[-1].split(':')[0]) self.bot.send_message(message.from_user.id, f"Ваше имя: {name}\nВаше ID: {user_id}") ask_name(message)
修复后完整代码
import telebot from telebot import types import gspread from registration_sheet import gs, sh from button import button1, button2, mm token = 'token' with open("C:/Users/nmash/Desktop/Cloud/terms_of_the_agreement.txt", encoding="utf-8") as f: terms_text = f.read() class Telegrambot(): def __init__(self, token): super(Telegrambot, self).__init__() self.bot = telebot.TeleBot(token, threaded=True) self.message_handler() self.start() def start(self): self.bot.polling(none_stop=True, interval=1) def message_handler(self): @self.bot.message_handler(content_types=['text', 'sticker', 'photo', 'voice', 'document']) def message_worker(message): if not message.text: self.bot.send_message(message.from_user.id, "Пожалуйста, отправляйте текстовые сообщения для работы с ботом") return if message.text == '/start': button1() self.bot.send_message(message.from_user.id, terms_text, reply_markup=mm) if message.text == "Принять условия соглашения✅": self.bot.send_message(message.from_user.id, "Вы приняли условия соглашения✅", reply_markup=types.ReplyKeyboardRemove()) self.registration(message) def registration(self, message): def ask_name(message): sent = self.bot.send_message(message.from_user.id, 'Введите своё имя:') self.bot.register_next_step_handler(sent, save_name) def save_name(message): if not message.text: self.bot.send_message(message.from_user.id, "Имя должно быть текстом, попробуйте снова:") self.bot.register_next_step_handler(message, save_name) return name = message.text.strip() worksheet = sh.sheet1 append_res = worksheet.append_row([name]) user_id = int(append_res['updates']['updatedRange'].split('A')[-1].split(':')[0]) self.bot.send_message(message.from_user.id, f"Ваше имя: {name}\nВаше ID: {user_id}") ask_name(message) Telegrambot(token=token)
内容的提问来源于stack exchange,提问作者Deoken
相关产品推荐
相关产品推荐

