Как повторить вебхук: отладка HTTP-запросов через Replay
Получите тестовый вебхук, найдите ошибку и повторите запрос после исправления. Рабочий пример на Python, диагностика подписей и ограничения Replay.

Повтор вебхука нужен, когда запрос уже пришёл, но обработчик завершился ошибкой. Вместо нового события у отправителя можно отправить сохранённый HTTP-запрос ещё раз. В TunnelHunt это делает кнопка Replay в журнале запросов.
Ниже воспроизведём ошибку на небольшом обработчике, исправим её и повторим событие. Пример работает с искусственными данными и не вызывает платёжные операции.
1. Запустите обработчик с воспроизводимой ошибкой
Сохраните как webhook_demo.py. Нужен Python 3, сторонние пакеты не требуются:
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
REQUIRE_CUSTOMER = True
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path != '/webhook':
self.send_error(404)
return
size = int(self.headers.get('Content-Length', '0'))
if size > 65536:
self.send_error(413)
return
try:
event = json.loads(self.rfile.read(size))
if not isinstance(event, dict):
raise ValueError('Expected a JSON object')
except (ValueError, UnicodeDecodeError):
self.send_error(400)
return
# Искусственная ошибка: старый обработчик требует лишнее поле.
status = 500 if REQUIRE_CUSTOMER and 'customer' not in event else 200
body = json.dumps({'event_id': event.get('id'), 'status': status}).encode()
self.send_response(status)
self.send_header('Content-Type', 'application/json')
self.send_header('Content-Length', str(len(body)))
self.end_headers()
self.wfile.write(body)
HTTPServer(('127.0.0.1', 3000), Handler).serve_forever()
python3 webhook_demo.py
В другом терминале откройте туннель. Чтобы найти его логи в своём кабинете, используйте SSH-ключ, связанный с вашим аккаунтом:
ssh -p 2222 -R 80:127.0.0.1:3000 tunnelhunt.ru
2. Отправьте тестовое событие
Замените домен в команде на адрес из терминала:
curl -i https://YOUR-SUBDOMAIN.tunnelhunt.ru/webhook \
-H 'Content-Type: application/json' \
--data '{"id":"demo-001","type":"order.created"}'
Ожидается 500: в теле нет customer, а обработчик пока требует это поле. Запрос с тем же телом к http://127.0.0.1:3000/webhook даст такой же результат.
3. Найдите запрос в журнале
Откройте панель TunnelHunt, выберите свой туннель и журнал HTTP-запросов. Найдите POST /webhook по времени отправки.
Проверьте метод, путь, Content-Type, сохранённое тело и статус. Если записи нет, сначала убедитесь, что смотрите правильный туннель и используете ключ своего аккаунта. Доступность и срок хранения логов зависят от условий тарифа.
4. Исправьте код и нажмите Replay
Измените REQUIRE_CUSTOMER = True на False. Остановите только Python-процесс через Ctrl+C и запустите его снова. SSH-соединение оставьте работающим, чтобы адрес сохранился.
Нажмите Replay для исходного запроса. В локальном журнале должен появиться новый POST /webhook со статусом 200. Так вы проверите исправление на том же событии demo-001.
Без панели можно повторить команду curl из шага 2. Разница в том, что Replay использует доступную сохранённую копию, а в curl вы самостоятельно задаёте метод, тело и заголовки.
Почему повтор не всегда равен новой доставке
Replay повторяет HTTP-обращение, но не создаёт новое событие в платёжной системе или Telegram. Состояние отправителя остаётся прежним, а состояние вашей базы могло уже измениться.
- Подпись и время. Если подпись ограничена по времени, сохранённый запрос может больше не пройти проверку. Не отключайте проверку ради Replay; используйте свежую тестовую доставку или изолированный тест проверки подписи.
- Идемпотентность. Обработанный
event_idможет быть отклонён как дубль. Это ожидаемое поведение. Проверяйте, что повтор не создаёт вторую оплату, отправку или запись. - IP-адрес. Повтор приходит через инфраструктуру туннеля, а не из сети исходного провайдера. Проверку IP нельзя тестировать таким повтором как полную имитацию реальной доставки.
- Размер тела. В текущей реализации в журнал сохраняются первые 2 МиБ тела запроса. Для большего payload сохранённая копия может быть неполной; сравните с исходником перед повтором.
- Транспорт. Служебные заголовки вроде
Host,ConnectionиContent-Lengthпри отправке формируются заново. Это не побайтовое воспроизведение TCP-сессии.
Что означает ошибка после повтора
| Результат | Где искать причину |
|---|---|
404 |
Путь обработчика изменился или выбран другой туннель |
400 |
Формат тела, кодировка или обязательные поля |
401 / 403 |
Токен, подпись, срок действия или политика доступа |
409 либо ответ о дубликате |
Событие уже обработано |
500 |
Исключение в локальном обработчике; смотрите его журнал |
502 |
Локальное приложение или SSH-соединение недоступны |
Для рабочего проекта замените демонстрационный обработчик своим тестовым endpoint. Примеры интеграций: Telegram, платёжные вебхуки и n8n.
Готовы запустить свой первый туннель?
Начните использовать TunnelHunt бесплатно уже сегодня и откройте доступ к локальному серверу всего одной командой.
Зарегистрироваться бесплатно →По теме

n8n локально: вебхуки и Telegram Trigger через HTTPS-туннель
11 сентября 2026 г.
Настраиваем публичный URL для n8n на localhost: Docker Compose, N8N_WEBHOOK_URL, тестовый и рабочий webhook, Telegram Trigger и диагностика ошибок.

Telegram-бот локально: webhook, secret_token и отладка на localhost
5 июня 2025 г.
Запустите Telegram-бота на localhost: выберите polling или webhook, настройте HTTPS и secret_token, проверьте getWebhookInfo и исправьте ошибки доставки.

MCP-сервер TunnelHunt: проверенный запуск, HTTP-запрос и остановка
16 июня 2026 г.
Практический тест @tunnelhunt/mcp 1.0.1: настройка SSH, start_tunnel, ответ локального API, get_tunnel_logs и stop_tunnel. Ограничения и ошибки подключения.

Как открыть localhost в интернете: публичный HTTPS через SSH
11 сентября 2026 г.
Пошагово открываем локальный сайт из интернета без настройки роутера: SSH-туннель, проверка ссылки, Docker, Vite и диагностика ошибок.