docker 在webhook上的aigram bot中未调用消息处理程序

dluptydi  于 2022-11-03  发布在  Docker
关注(0)|答案(1)|浏览(153)

我在本地使用ngrok隧道在webhook上启动了一个aigram bot,但是bot返回的不是正确的响应,而是200 OK,响应正文中几乎没有任何内容,因此用户在聊天中看不到任何内容。
Bot的main.py驱动程序如下所示:

from aiogram import executor

from loader import dp, bot, cache
from handlers import register_start_handlers, register_main_handlers
from settings import Settings, get_settings

config: Settings = get_settings()

async def on_startup(dispatcher):
    await bot.set_webhook(config.webhook.address)

register_start_handlers(dp)
register_main_handlers(dp)

async def on_shutdown(dispatcher):
    await bot.delete_webhook()
    await dispatcher.storage.close()
    await dispatcher.storage.wait_closed()
    await cache.close()
    await cache.wait_closed()

if __name__ == "__main__":
    setup_logging()
    executor.start_webhook(
        dispatcher=dp,
        webhook_path=config.webhook.WEBHOOK_PATH,
        on_startup=on_startup,
        on_shutdown=on_shutdown,
        skip_updates=True,
        host=config.webhook.BOT_WEBAPP_HOST,
        port=config.webhook.BOT_WEBAPP_PORT,
    )

handlers模块中的消息处理程序是通过如下函数注册的:

from aiogram import Dispatcher
from aiogram.types import Message
from aiogram.dispatcher.webhook import SendMessage

async def begin_interaction(message: Message):
    return SendMessage(message.from_user.id, "Message text")

def register_start_handlers(dp: Dispatcher):
    dp.register_message_handler(begin_interaction, commands=["start"])

这些设置来自项目根目录中的.env文件,检索方式如下:

from pydantic import validator, BaseSettings

BASE_DIR = pathlib.Path(__file__).parent

class EnvSettings(BaseSettings):
    class Config(BaseSettings.Config):
        env_file = "../.env"

...

class WebhookSettings(EnvSettings):
    WEBHOOK_HOST: str
    WEBHOOK_PATH: str
    BOT_WEBAPP_HOST: str
    BOT_WEBAPP_PORT: int

    @property
    def address(self) -> str:
        return f"{self.WEBHOOK_HOST}{self.WEBHOOK_PATH}"

class Settings:
    ...
    webhook: WebhookSettings = WebhookSettings()

bot连接到几个微服务,所有这些微服务都是使用docker-compose启动的,因此环境变量看起来像这样:

WEBHOOK_HOST='https://some.subdomain.ngrok.io'
WEBHOOK_PATH='/'

BOT_WEBAPP_HOST=0.0.0.0
BOT_WEBAPP_PORT=3001

我不得不使用0.0.0.0(或工作方式相同的Docker网络本地IP)作为HOST,因为official docs推荐的localhost导致应用程序失败,并出现以下错误:OSError: [Errno 99] error while attempting to bind on address ('::1', 3001, 0, 0): cannot assign requested address
我认为这并不重要,因为示例应用程序(同样,像official one)在localhost0.0.0.0(也使用相同的ngrok设置)上都能很好地工作。
现在,问题来了。使用上面的设置,应用程序正常启动,但是对来自Telegram的POST请求没有返回预期的响应(用ngrok的inspect页面检查了这一点).相反,它只返回200 OK给任何在主体中只有ok的请求,并且没有Telegram可以转换为消息来响应的数据.简单的实验表明消息处理程序是注册的,但不叫,这很奇怪:同样的机器人结构在更简单的测试机器人上工作得很好。2而且这个项目本身在使用长轮询时也工作得很好,所以整体结构看起来或多或少是功能性的。
我尝试编写一个最小的可重现示例来复制错误,但没有成功(我设计的所有简单程序都能很好地在此设置下工作),所以我只是希望能对问题所在进行一些推测。我一直在尝试更改.env中的IP地址和端口,但这从来没有工作过。在Docker中启动也不是问题,因为当我试图在容器外部启动时,会在Docker-compose文件中暴露必要的端口,一切都差不多。

atmip9wb

atmip9wb1#

事实证明,问题出在机器人的结构上。我使用了aiogram的内置FSM工具,它为与特定用户的对话分配一个状态值,并允许您根据该值过滤消息:

@message_handler(state=Manager.choose_action)
async def f(message: Message, state: FSMContext):
    ...

看起来,在测试过程中,我关闭了一次Docker容器,但是它们保留了bot的状态数据,并且在我下一次启动bot服务时,与该状态关联的消息处理程序捕获了所有消息,但没有返回任何内容,因为它们没有处理程序所期望的数据。
所以,这基本上是我的错,但这是一个坚韧捕捉的错误。如果你遇到了像我这样的情况,尝试取消你的状态(比如使用/cancel命令)或清除持久化的bot数据,这可能会有所帮助

相关问题