使用webhook替代infinity_polling():ngrok无法接收Telegram更新求助
问题描述
我正尝试基于PyTelegramBotAPI的webhook_aiohttp示例模板,为现有代码添加webhook以替代infinity_polling(),但使用ngrok时无法接收Telegram的任何更新。以下是我的操作步骤、项目结构及相关代码,求正确配置webhook的方法。
操作步骤
- 终端执行:
python -m SimpleHTTPServer 8443
- 进入项目目录
- 启动ngrok:
ngrok http 8443
终端输出:
======== Running on http://localhost:8443 ======== (Press CTRL+C to quit)
项目结构
- database:database.py
- handlers:account.py、buy.py、join_group.py、shipping_handlers.py、start.py
- config.py
- main.py
原main.py代码(使用polling)
from telebot import TeleBot from membership_bot import config from membership_bot.handlers.buy import buyHandlerTest, buyHandler from membership_bot.handlers.join_group import joinGroupHandler from membership_bot.handlers.start import startHandler, backHomeHandler from membership_bot.handlers.shipping_handlers import checkout, got_payment from membership_bot.handlers.account import accountHandler bot = TeleBot(config.BOT_TOKEN) bot.register_message_handler(startHandler, commands=['start'], chat_types=['private'], pass_bot=True) bot.register_callback_query_handler(joinGroupHandler, func=lambda message: message.data == "join_group", pass_bot=True) bot.register_callback_query_handler(accountHandler, func=lambda message: message.data == "account", pass_bot=True) bot.register_callback_query_handler(backHomeHandler, func=lambda message: message.data == "back_home", pass_bot=True) bot.register_callback_query_handler(buyHandler, func=lambda message: message.data.startswith('Buy'), pass_bot=True) bot.register_pre_checkout_query_handler(checkout, func=lambda query: True, pass_bot=True) bot.register_message_handler(got_payment, content_types=['successful_payment'], pass_bot=True) bot.infinity_polling()
基于模板修改的webhook版代码
import logging from aiohttp import web import telebot API_TOKEN = 'MyToken' WEBHOOK_HOST = '123.eu.ngrok.io' WEBHOOK_PORT = 8443 # 443, 80, 88 or 8443 (port need to be 'open') WEBHOOK_LISTEN = 'localhost' WEBHOOK_URL_BASE = "https://{}:{}".format(WEBHOOK_HOST, WEBHOOK_PORT) WEBHOOK_URL_PATH = "/{}/".format(API_TOKEN) logger = telebot.logger telebot.logger.setLevel(logging.INFO) bot = telebot.TeleBot(API_TOKEN) app = web.Application() # Process webhook calls async def handle(request): logging.info('Called handle requests........') if request.match_info.get('token') == bot.token: request_body_dict = await request.json() update = telebot.types.Update.de_json(request_body_dict) bot.process_new_updates([update]) return web.Response() else: return web.Response(status=403) app.router.add_post('/{token}/', handle) # Handle '/start' and '/help' @bot.message_handler(commands=['help', 'start']) def send_welcome(message): logging.info('Called start command........') bot.reply_to(message, ("Hi there, I am EchoBot.\n" "I am here to echo your kind words back to you.")) # Handle all other messages @bot.message_handler(func=lambda message: True, content_types=['text']) def echo_message(message): bot.reply_to(message, message.text) # Remove webhook, it fails sometimes the set if there is a previous webhook logging.info('Removing webhook........') bot.remove_webhook() logging.info('Webhook removed........') # Set webhook logging.info('Setting webhook........') bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH) logging.info('Webhook set........') # Start aiohttp server web.run_app( app, host=WEBHOOK_LISTEN, port=WEBHOOK_PORT )
解决方案
核心问题排查
- 端口冲突与服务顺序错误:先启动
SimpleHTTPServer 8443会占用端口,导致后续aiohttp bot服务器无法启动,且ngrok转发的是静态服务器端口,并非bot服务。 - Webhook地址配置错误:ngrok提供的HTTPS地址无需附加端口(已自动将本地8443映射到其443端口),你的
WEBHOOK_URL_BASE多了端口号,导致Telegram无法正确推送更新。 - 服务器监听地址错误:
WEBHOOK_LISTEN = 'localhost'会限制服务器仅接受本地请求,ngrok转发的外部请求无法抵达bot服务。 - 未整合原有业务Handler:测试代码用了示例的echo handler,未导入原项目业务逻辑,即使收到更新也无法执行原有功能。
正确配置步骤
- 释放8443端口:关闭所有占用该端口的服务(如之前启动的
SimpleHTTPServer)。 - 启动ngrok:执行
ngrok http 8443,复制输出中的https://xxxx-xx-xx-xx-xx.eu.ngrok.io地址(不带端口)。 - 修改webhook版代码:调整配置并整合原有业务逻辑,代码如下:
修改后的完整webhook版main.py代码
import logging from aiohttp import web import telebot from membership_bot import config from membership_bot.handlers.buy import buyHandlerTest, buyHandler from membership_bot.handlers.join_group import joinGroupHandler from membership_bot.handlers.start import startHandler, backHomeHandler from membership_bot.handlers.shipping_handlers import checkout, got_payment from membership_bot.handlers.account import accountHandler # 日志配置 logger = telebot.logger telebot.logger.setLevel(logging.INFO) # 初始化Bot bot = telebot.TeleBot(config.BOT_TOKEN) # === 注册原有业务Handler === bot.register_message_handler(startHandler, commands=['start'], chat_types=['private'], pass_bot=True) bot.register_callback_query_handler(joinGroupHandler, func=lambda message: message.data == "join_group", pass_bot=True) bot.register_callback_query_handler(accountHandler, func=lambda message: message.data == "account", pass_bot=True) bot.register_callback_query_handler(backHomeHandler, func=lambda message: message.data == "back_home", pass_bot=True) bot.register_callback_query_handler(buyHandler, func=lambda message: message.data.startswith('Buy'), pass_bot=True) bot.register_pre_checkout_query_handler(checkout, func=lambda query: True, pass_bot=True) bot.register_message_handler(got_payment, content_types=['successful_payment'], pass_bot=True) # Webhook配置(替换为你的ngrok HTTPS地址) WEBHOOK_HOST = 'xxxx-xx-xx-xx-xx.eu.ngrok.io' # ngrok输出的域名部分,不带https和端口 WEBHOOK_PORT = 8443 WEBHOOK_LISTEN = '0.0.0.0' # 允许外部请求访问 WEBHOOK_URL_BASE = f"https://{WEBHOOK_HOST}" # ngrok的https地址,不需要端口 WEBHOOK_URL_PATH = f"/{config.BOT_TOKEN}/" # 使用配置文件里的token,避免硬编码 # 初始化aiohttp应用 app = web.Application() # Webhook请求处理函数 async def handle(request): logging.info('收到Telegram更新请求') if request.match_info.get('token') == bot.token: try: request_body_dict = await request.json() update = telebot.types.Update.de_json(request_body_dict) bot.process_new_updates([update]) return web.Response(status=200) except Exception as e: logging.error(f"处理更新失败: {str(e)}") return web.Response(status=500) else: return web.Response(status=403) # 注册POST路由 app.router.add_post(f"/{{token}}/", handle) # 设置Webhook if __name__ == '__main__': logging.info('正在移除旧Webhook...') bot.remove_webhook() logging.info('旧Webhook已移除') logging.info('正在设置新Webhook...') bot.set_webhook(url=WEBHOOK_URL_BASE + WEBHOOK_URL_PATH) logging.info(f"Webhook已设置为: {WEBHOOK_URL_BASE + WEBHOOK_URL_PATH}") # 启动aiohttp服务器 logging.info(f"服务器启动,监听{WEBHOOK_LISTEN}:{WEBHOOK_PORT}") web.run_app( app, host=WEBHOOK_LISTEN, port=WEBHOOK_PORT )
验证步骤
- 运行修改后的
main.py:python main.py - 给Bot发送
/start命令,查看终端日志是否输出收到Telegram更新请求及相关业务日志 - 若仍无响应:
- 检查ngrok终端是否有
POST /your-bot-token/的请求记录:无记录则Webhook地址配置错误;有记录但返回403则token匹配失败;返回200但bot无响应则检查handler注册是否正确。
- 检查ngrok终端是否有
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

