Назад к статьям

Webhook или long polling: что выбрать для бота

Telegram доставляет обновления боту двумя способами: long polling (бот сам опрашивает сервер) и webhook (Telegram шлёт POST на ваш URL). В статье — как это устроено и как переключиться с одного на другое.

Long polling

Бот в цикле вызывает getUpdates: получил обновления — обработал — запросил следующие с offset. Плюсы: не нужен домен с SSL и белый IP, удобно на разработке и на простом VPS. Минусы: небольшая задержка, бот должен быть постоянно запущен.

В aiogram long polling включается по умолчанию при dp.start_polling(bot). Ниже — пример «ручного» цикла на requests, чтобы понять механику (в проде лучше использовать aiogram):

import requests BOT_TOKEN = "..." def get_updates(offset=None): url = f"https://api.telegram.org/bot{BOT_TOKEN}/getUpdates" r = requests.get(url, params={"timeout": 30, "offset": offset}, timeout=35) return r.json().get("result", []) offset = None while True: updates = get_updates(offset) for u in updates: offset = u["update_id"] + 1 if "message" in u: chat_id = u["message"]["chat"]["id"] requests.get(f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage", params={"chat_id": chat_id, "text": "Получил: " + u["message"].get("text", "")})

Webhook

Вы указываете HTTPS-URL; Telegram при каждом событии (сообщение, callback) отправляет туда POST с телом Update. Плюсы: быстрая доставка, не нужно держать длинный запрос. Минусы: нужен домен с SSL и доступный порт 443 (или прокси, например nginx).

Установка webhook и приём обновлений (aiohttp + aiogram): при старте приложения вызывается on_startup — ставится webhook; при остановке — on_shutdown, webhook удаляется. Обработчики регистрируются в dp как обычно.

from aiohttp import web from aiogram import Bot, Dispatcher from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application WEBHOOK_PATH = "/webhook" WEBHOOK_URL = "https://yourdomain.com" + WEBHOOK_PATH async def on_startup(bot: Bot): await bot.set_webhook(WEBHOOK_URL) async def on_shutdown(bot: Bot): await bot.delete_webhook() bot = Bot(token="...") dp = Dispatcher() # ... регистрация handlers (dp.message, dp.callback_query и т.д.) ... app = web.Application() webhook_requests = SimpleRequestHandler(dispatcher=dp, bot=bot) webhook_requests.register(app, path=WEBHOOK_PATH) setup_application(app, dp, bot=bot) if __name__ == "__main__": app.on_startup.append(lambda app: on_startup(bot)) app.on_shutdown.append(lambda app: on_shutdown(bot)) web.run_app(app, host="0.0.0.0", port=8080) # 443 с SSL или за nginx

В проде часто поднимают приложение на порту 8080, а nginx на 443 принимает HTTPS и проксирует запросы на http://127.0.0.1:8080/webhook. Тогда в WEBHOOK_URL указываете https://yourdomain.com/webhook. SSL для nginx — например Certbot (Let's Encrypt).

Переход с long poll на webhook

  1. Убедитесь, что webhook не установлен: getWebhookInfo — поле url должно быть пустым (или удалите через deleteWebhook).
  2. Поднимите HTTPS-сервер с путём для webhook и зарегистрируйте URL: setWebhook(url="https://yourdomain.com/webhook").
  3. Запустите приложение. Дальше Telegram будет слать обновления только на webhook; long polling при активном webhook не используется.

Что выбрать

Для разработки и тестов удобнее long polling. Для продакшена с большой нагрузкой и минимальной задержкой — webhook с SSL за nginx.

Итоги

Long polling проще в настройке и не требует домена с SSL. Webhook даёт быструю доставку и подходит для продакшена. Выбор зависит от этапа проекта и инфраструктуры.