Получаем updates через webhook
Результат
Вы поднимете локальный webhook endpoint, включите push-доставку, проверите секретный заголовок и вернёте gateway в polling mode без потери очереди.
Что понадобится
- пройденный быстрый старт;
- запущенный gateway профиля
telegram-v1-core-preview-4на127.0.0.1:8081; - Python 3,
curlиjq; - свободный локальный порт
9000.
export SKREPA_BOT_API='http://127.0.0.1:8081'
export SKREPA_BOT_TOKEN='ваш-token-из-BotFather'
export SKREPA_WEBHOOK_SECRET="$(openssl rand -hex 32)"
set -o pipefail
printf 'Скопируйте секрет во второй терминал: %s\n' "$SKREPA_WEBHOOK_SECRET"
HTTP разрешён для loopback-адресов. Публичный endpoint должен использовать HTTPS и быть достижим из сети, где запущен gateway.
1. Запустите приёмник
Создайте webhook.py:
import hmac
import json
import os
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
SECRET = os.environ["SKREPA_WEBHOOK_SECRET"]
class Handler(BaseHTTPRequestHandler):
def do_POST(self) -> None:
received = self.headers.get("X-Telegram-Bot-Api-Secret-Token", "")
if not hmac.compare_digest(received, SECRET):
self.send_error(403)
return
try:
length = int(self.headers.get("Content-Length", "0"))
if length < 0:
raise ValueError("negative Content-Length")
except ValueError:
self.send_error(400, "invalid Content-Length")
return
try:
update = json.loads(self.rfile.read(length))
except json.JSONDecodeError:
self.send_error(400, "invalid JSON")
return
print(json.dumps(update, ensure_ascii=False), flush=True)
self.send_response(204)
self.end_headers()
def log_message(self, _format: str, *_args: object) -> None:
pass
ThreadingHTTPServer(("127.0.0.1", 9000), Handler).serve_forever()
Запустите его в отдельном терминале, подставив напечатанный выше секрет:
export SKREPA_WEBHOOK_SECRET='скопированный-секрет'
python3 webhook.py
2. Включите webhook mode
В исходном терминале выполните:
curl --fail-with-body -sS \
-H 'content-type: application/json' \
-d "$(jq -n \
--arg secret "$SKREPA_WEBHOOK_SECRET" \
'{url:"http://127.0.0.1:9000/update", secret_token:$secret,
allowed_updates:["message"], max_connections:1}')" \
"$SKREPA_BOT_API/bot${SKREPA_BOT_TOKEN}/setWebhook" | jq .
Проверьте конфигурацию:
curl --fail-with-body -sS \
"$SKREPA_BOT_API/bot${SKREPA_BOT_TOKEN}/getWebhookInfo" | jq .
Ожидаются URL http://127.0.0.1:9000/update, max_connections: 1,
allowed_updates: ["message"] и отсутствие ошибки доставки.
3. Получите update
Отправьте боту сообщение из клиента Скрепы. Терминал с webhook.py напечатает
JSON-объект Update. Повторная доставка того же update_id допустима, поэтому
production-обработчик должен сначала надёжно записать результат и лишь затем
возвращать 2xx.
Убедитесь, что polling заблокирован во время работы webhook:
curl -sS -o /tmp/skrepa-polling-conflict.json -w 'HTTP %{http_code}\n' \
"$SKREPA_BOT_API/bot${SKREPA_BOT_TOKEN}/getUpdates"
jq . /tmp/skrepa-polling-conflict.json
rm -f /tmp/skrepa-polling-conflict.json
Ответ должен иметь HTTP 409.
4. Вернитесь к polling
curl --fail-with-body -sS -X POST \
"$SKREPA_BOT_API/bot${SKREPA_BOT_TOKEN}/deleteWebhook" | jq .
По умолчанию pending updates сохраняются. Параметр
drop_pending_updates=true удаляет их необратимо и нужен лишь при сознательном
отказе от накопленной очереди. Остановите webhook.py с помощью Ctrl+C.
Как понять, что всё получилось
setWebhookвернулok: true;getWebhookInfoпоказал локальный URL,max_connections: 1иallowed_updates: ["message"];- приёмник получил update с правильным секретным заголовком;
getUpdatesвернул409в webhook mode;deleteWebhookвосстановил polling mode.
Типичные ошибки
| Симптом | Что проверить |
|---|---|
last_error_message содержит connection refused | приёмник запущен, порт и адрес совпадают, URL достижим из network namespace gateway |
приёмник отвечает 403 | секрет в процессе приёмника совпадает с secret_token из setWebhook |
| внешний HTTP URL отклонён | используйте HTTPS; незашифрованный HTTP разрешён лишь для loopback |
| update приходит повторно | предыдущая попытка завершилась без 2xx или ответ потерялся; дедуплицируйте по update_id |
| новые updates стоят в очереди | головной update получает timeout/non-2xx; исправьте endpoint и проверьте getWebhookInfo |
Что гарантирует gateway
- polling и webhook используют одну упорядоченную pending queue;
- переключение режима и очистка через
drop_pending_updatesвыполняются атомарно; - HTTP
2xxподтверждает текущий головной update, остальные статусы и сетевые ошибки запускают повтор с ограниченной экспоненциальной задержкой; - доставка последовательна и сохраняет порядок (
max_connections=1); secret_tokenпередаётся только в заголовкеX-Telegram-Bot-Api-Secret-Token;- webhook-конфигурация, pending updates и последняя ошибка переживают перезапуск gateway.