Чтобы протестировать веб-хук бота Telegram на локальном хосте, откройте свой локальный сервер с помощью общедоступного HTTPS-туннеля, вызовите setWebhook с этим URL-адресом и проверяйте заголовок секретного токена Telegram при каждом запросе. Это дает вам реальные сообщения, запросы обратного вызова и обновления членства без развертывание после каждого изменения кода. Полный цикл таков: запустите обработчик бота, запустите npx portpreview 3000, зарегистрируйте полученный URL-адрес, отправьте боту сообщение и проверьте запрос локально.
Почему Telegram не может отправлять обновления напрямую на локальный хост
API-интерфейс Telegram Bot отправляет обновления веб-перехватчика из инфраструктуры Telegram на URL-адрес, доступный в Интернете. localhost, 127.0.0.1 и частные адреса локальной сети не маршрутизируются из этой инфраструктуры. Туннель localhost завершает HTTPS по публичному адресу и перенаправляет неизмененный HTTP-запрос на ваш локальный порт.
Боты Telegram могут получать обновления двумя взаимоисключающими способами: длинным опросом через getUpdates или веб-перехватчиками. В официальной ссылке ⟧setWebhook указано, что getUpdates недоступен, пока настроен исходящий веб-перехватчик. Если процесс опроса все еще выполняется, остановите его, прежде чем оценивать поток веб-перехватчика.
Создание локальной конечной точки веб-перехватчика
В этом примере Express обработчик намеренно сделан маленьким. Он проверяет общий секрет перед обновлением, быстро подтверждает и перемещает работу за пределы пути ответа.
import express from 'express';
import crypto from 'node:crypto';
const app = express();
app.use(express.json({ limit: '1mb' }));
function sameSecret(received = '', expected = '') {
const a = Buffer.from(received);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post('/webhooks/telegram', (req, res) => {
const received = req.get('x-telegram-bot-api-secret-token') || '';
if (!sameSecret(received, process.env.TELEGRAM_WEBHOOK_SECRET)) {
return res.sendStatus(401);
}
const update = req.body;
res.sendStatus(200);
queueMicrotask(() => handleUpdate(update));
});
app.listen(3000, () => console.log('Listening on http://localhost:3000'));
Telegram отправляет Update в формате JSON. В отличие от поставщиков на базе HMAC, функция Telegram secret_token не подписывает тело сообщения. Выбранное вами значение помещается в X-Telegram-Bot-Api-Secret-Token. Токен доказывает, что отправителю известно значение, использованное при регистрации веб-перехватчика, но он не предоставляет дайджест полезной нагрузки. TLS защищает запрос при передаче.
Предоставить конечную точку с помощью HTTPS
- Запустите приложение и подтвердите, что
curl -i http://localhost:3000/webhooks/telegramдостигает сервера, даже если GET вернет 404. - Откройте второй терминал и запустите
npx portpreview 3000. - Скопируйте общедоступный источник HTTPS и добавьте
/webhooks/telegram. - Оставьте процесс туннеля запущенным, пока Telegram доставляет обновления.
API бота принимает URL-адреса веб-перехватчиков HTTPS. Telegram документирует поддержку веб-перехватчиков на портах 443, 80, 88 и 8443; общедоступная конечная точка управляемого туннеля обычно использует 443, даже если перенаправленный локальный процесс прослушивает 3000.
Безопасная регистрация веб-перехватчика Telegram
Создайте случайный секрет, содержащий только буквы, цифры, символы подчеркивания или дефисы. Telegram допускает длину от 1 до 256 символов. Не используйте повторно токен бота в качестве этого значения.
export TELEGRAM_WEBHOOK_SECRET="$(openssl rand -hex 32)"
curl -sS -X POST \
"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setWebhook" \
-d "url=https://YOUR-TUNNEL.portpreview.dev/webhooks/telegram" \
-d "secret_token=${TELEGRAM_WEBHOOK_SECRET}" \
-d 'allowed_updates=["message","callback_query"]' \
-d "drop_pending_updates=true"
allowed_updates уменьшает шум и должен перечислять только типы обновлений, которые обрабатывает бот. drop_pending_updates=true полезен при запуске нового локального сеанса, но он навсегда отбрасывает обновления в очереди, поэтому опускайте его, когда эти события имеют значение. Обновленная документация Telegram описывает такие поля, как message, callback_query и my_chat_member.
Подтвердите регистрацию перед отладкой кода
Используйте getWebhookInfo, чтобы отделить ошибки конфигурации от ошибок обработчика:
curl -sS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getWebhookInfo"
Проверьте url, pending_update_count, last_error_message и last_error_date. Пустой URL-адрес означает, что регистрация не сохранилась. Растущее количество ожидающих запросов обычно означает, что Telegram не может подключиться или ваша конечная точка возвращает статус, отличный от 2xx. Отправьте сообщение боту в директ после регистрации; простое открытие чата не обязательно приводит к обновлению.
Обработка обновлений без повторных попыток
Подтвердить перед медленной работой
Вернуть ответ 2xx, как только запрос будет аутентифицирован и окончательно принят. Экспорт базы данных, вызовы искусственного интеллекта и сторонние API должны выполняться асинхронно. Telegram повторяет неудачные запросы после ответов, отличных от 2xx, поэтому медленная синхронная работа может создавать дубликаты.
Дедупликация с update_id
Каждое обновление имеет update_id. Сохраняйте обработанные идентификаторы с указанием срока действия или используйте уникальный ключ базы данных. При повторной попытке не следует отправлять вторую квитанцию об оплате, создавать дубликат заявки или дважды выполнять один и тот же обратный вызов.
Моделируйте каждый тип обновления явно
Не каждое обновление содержит message.text. Кнопки обратного вызова находятся под callback_query; Публикации на канале и изменения в членстве имеют другие поля. Разветвляйтесь по текущему полю верхнего уровня и обрабатывайте неизвестные типы как допустимые пустые операции, а не выбрасывающие.
Правила безопасности для локального тестирования ботов Telegram
- Сначала проверьте секретный заголовок. Отклоняйте отсутствующие или неправильные значения перед регистрацией или анализом конфиденциальных полей.
- Не допускайте попадания токенов в URL-адреса и журналы. Токен Bot API в команде регистрации является учетными данными. Избегайте истории оболочки в общих системах и меняйте открытый токен через BotFather.
- Используйте неугаданный и секретный маршрут. Маршрут представляет собой глубокоэшелонированную защиту; секретный заголовок — это фактическая проверка приложения.
- Ограничить перехват данных. Сообщения могут содержать имена, имена пользователей, номера телефонов, файлы и текст частной беседы. Отредактируйте журналы и удалите локальные записи, когда закончите.
- Никогда не отключайте аутентификацию в процессе разработки. Публичный туннель является общедоступным. Локальный код должен выполнять те же проверки, что и производственный.
См. более подробное руководство по безопасности туннеля локального хоста для получения информации о методах контроля доступа и хранения данных.
Устранение распространенных неполадок веб-перехватчика Telegram
Telegram сообщает об ошибке сертификата или соединения
Используйте URL-адрес HTTPS туннеля, а не его локальную цель HTTP. Убедитесь, что туннель активен и URL-адрес не изменился. Если вместо этого вы предоставите собственный самозаверяющий сертификат, Telegram потребует загрузить общедоступный сертификат в виде файла; управляемая конечная точка TLS позволяет избежать такой настройки.
Конечная точка возвращает 401
Сравните секрет, переданный в setWebhook, с переменной среды, используемой процессом. Имена заголовков не чувствительны к регистру, но прокси-серверы или промежуточное программное обеспечение могут удалять пользовательские заголовки. Проверьте входящие заголовки, не печатая секретное значение.
Запросы не поступают
Запустите getWebhookInfo, убедитесь, что зарегистрированный путь точно соответствует вашему маршруту, и убедитесь, что никакой брандмауэр не блокирует локальное соединение туннеля. Если вы недавно использовали опрос, убедитесь, что URL-адрес веб-перехватчика теперь заполнен. Запустите актуальное обновление, отправив сообщение боту.
Обновления приходят неоднократно
Состояние журнала и время ответа. Исключения после получения запроса могут превратить запланированное 200 в 500. Возвращайте 200 сразу же, делайте обработку идемпотентной и используйте контролируемое воспроизведение веб-перехватчика вместо ожидания повторных попыток поставщика во время отладки.
Проверка запросов обратного вызова и файлов, а не только текста
Полезная матрица тестирования ботов охватывает более message.text. Отправьте фотографию с подписью, поделитесь контактом, отредактируйте сообщение и нажмите кнопку на встроенной клавиатуре. Для запросов обратного вызова немедленно вызовите answerCallbackQuery, чтобы клиент перестал показывать индикатор выполнения, а затем выполните более медленную работу отдельно. Обновления файлов содержат идентификаторы; загрузка байтов — это вторая операция API бота, которая не должна задерживать ответ веб-перехватчика.
Сохраняйте исправления, созданные из очищенных обновлений для модульных тестов, но сохраняйте полный путь транспортировки хотя бы для одного теста каждого поддерживаемого типа. Крепеж доказывает, что ваш диспетчер понимает полезную нагрузку; реальная туннельная доставка также подтверждает регистрацию, TLS, заголовки, анализ тела и поведение подтверждения. При добавлении новой записи allowed_updates снова вызовите setWebhook и убедитесь, что getWebhookInfo отражает предполагаемую конфигурацию.
Удалить вебхук после локального сеанса
curl -sS -X POST \
"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/deleteWebhook" \
-d "drop_pending_updates=false"
Удаление веб-перехватчика позволяет вернуться к getUpdates. Если URL-адрес туннеля изменится при следующем сеансе, позвоните по номеру setWebhook еще раз. Для дополнительной диагностики следуйте общему рабочему процессу отладки локального веб-перехватчика.
