Heroku部署Telegram Bot+Flask应用时webhook端口占用问题咨询
问题原因
- 核心原因是端口冲突:Heroku每个web进程仅分配一个公开端口,代码中先调用的
updater.start_webhook()会启动Telegram Bot自带的web服务占用该端口,后续执行app.run()启动Flask服务时,尝试绑定同一个端口就会触发Address already in use报错。 - 附加逻辑错误:命令处理函数
hellothere的定义、CommandHandler的注册逻辑都写在if __name__ == '__main__'之后,程序运行时不会执行这部分代码,即使解决端口问题,Bot的/hello命令也无法正常响应。 - 错误的webhook启动逻辑:将
updater.start_webhook()写在了/路由的处理函数里,webhook只需要在服务启动时设置一次,不需要每次收到根路径请求都重新启动webhook服务。
可行解决方案
推荐使用Flask服务统一处理Web路由和Bot webhook请求的方案,不需要启动两个独立web服务,修改后的app.py代码如下:
import os import telegram from telegram import Update from telegram.ext import CommandHandler, CallbackContext, Dispatcher from flask import Flask, render_template, request # 敏感信息建议存Heroku环境变量,不要硬编码 token = os.environ.get("TELEGRAM_BOT_TOKEN") heroku_app_name = os.environ.get("HEROKU_APP_NAME") app = Flask(__name__) bot = telegram.Bot(token=token) dp = Dispatcher(bot, None, workers=0) # 提前注册Bot命令 def hellothere(update: Update, context: CallbackContext): update.message.reply_text("Hello There!!") dp.add_handler(CommandHandler("hello", hellothere)) # Web应用路由 @app.route('/home') def home(): return render_template('home.html') # Bot webhook路由,接收Telegram推送的更新 @app.route(f'/{token}', methods=['POST']) def bot_webhook(): update = Update.de_json(request.get_json(force=True), bot) dp.process_update(update) return "ok", 200 if __name__ == '__main__': # 服务启动时设置一次webhook webhook_url = f"https://{heroku_app_name}.herokuapp.com/{token}" bot.set_webhook(webhook_url) # 只启动Flask服务即可 app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 5000)))
注:如果使用Flask 2.0+版本,不需要额外修改,上述逻辑可正常运行
如果需要同时运行Bot轮询模式和Web应用,可以拆分Heroku dyno,修改Procfile为:
web: gunicorn app:app worker: python bot.py
把Bot的逻辑单独拆分到bot.py文件中用轮询模式运行,web进程只负责Flask服务,该方案需要占用两个dyno配额。
内容的提问来源于stack exchange,提问作者Augusto
相关产品推荐
相关产品推荐

