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

使用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
    
)

解决方案

核心问题排查

  1. 端口冲突与服务顺序错误:先启动SimpleHTTPServer 8443会占用端口,导致后续aiohttp bot服务器无法启动,且ngrok转发的是静态服务器端口,并非bot服务。
  2. Webhook地址配置错误:ngrok提供的HTTPS地址无需附加端口(已自动将本地8443映射到其443端口),你的WEBHOOK_URL_BASE多了端口号,导致Telegram无法正确推送更新。
  3. 服务器监听地址错误:WEBHOOK_LISTEN = 'localhost'会限制服务器仅接受本地请求,ngrok转发的外部请求无法抵达bot服务。
  4. 未整合原有业务Handler:测试代码用了示例的echo handler,未导入原项目业务逻辑,即使收到更新也无法执行原有功能。

正确配置步骤

  1. 释放8443端口:关闭所有占用该端口的服务(如之前启动的SimpleHTTPServer)。
  2. 启动ngrok:执行ngrok http 8443,复制输出中的https://xxxx-xx-xx-xx-xx.eu.ngrok.io地址(不带端口)。
  3. 修改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
    )

验证步骤

  1. 运行修改后的main.py:python main.py
  2. 给Bot发送/start命令,查看终端日志是否输出收到Telegram更新请求及相关业务日志
  3. 若仍无响应:
    • 检查ngrok终端是否有POST /your-bot-token/的请求记录:无记录则Webhook地址配置错误;有记录但返回403则token匹配失败;返回200但bot无响应则检查handler注册是否正确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 01:46:18