Pour tester un webhook de robot Telegram sur localhost, exposez votre serveur local avec un tunnel HTTPS public, appelez setWebhook avec cette URL et validez l'en-tête de jeton secret de Telegram à chaque demande. Cela vous donne de vrais messages, requêtes de rappel et mises à jour d'adhésion. sans déployer après chaque changement de code. La boucle complète est la suivante : exécutez le gestionnaire de bot, démarrez npx portpreview 3000, enregistrez l'URL résultante, envoyez un message à votre bot et inspectez la demande localement.
Pourquoi Telegram ne peut pas envoyer de mises à jour directement à localhost
L'API Bot de Telegram envoie les mises à jour des webhooks depuis l'infrastructure Telegram vers une URL accessible sur Internet. localhost, 127.0.0.1 et les adresses LAN privées ne sont pas routables à partir de cette infrastructure. Un localhost tunnel termine HTTPS à une adresse publique et transmet la requête HTTP inchangée à votre port local.
Les robots Telegram peuvent recevoir des mises à jour de deux manières mutuellement exclusives : une longue interrogation via getUpdates ou des webhooks. La référence officielle setWebhook indique que getUpdates n'est pas disponible lorsqu'un webhook sortant est configuré. Si un processus d'interrogation est toujours en cours, arrêtez-le avant de juger le flux du webhook.
Créer un point de terminaison de webhook local
Cet exemple Express maintient le gestionnaire intentionnellement petit. Il vérifie le secret partagé avant de toucher à la mise à jour, reconnaît rapidement et déplace le travail en dehors du chemin de réponse.
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 envoie un Update sérialisé en JSON. Contrairement aux fournisseurs basés sur HMAC, la fonctionnalité secret_token de Telegram ne signe pas le corps. Il place la valeur que vous avez choisie dans X-Telegram-Bot-Api-Secret-Token. Le jeton prouve que l'expéditeur connaît la valeur utilisée lors de l'enregistrement du webhook, mais il ne fournit pas de résumé de la charge utile. TLS protège la demande en transit.
Exposez le point de terminaison avec HTTPS
- Démarrez l'application et confirmez que
curl -i http://localhost:3000/webhooks/telegramatteint le serveur, même si GET renvoie 404. - Ouvrez un deuxième terminal et exécutez
npx portpreview 3000. - Copiez l'origine HTTPS publique et ajoutez
/webhooks/telegram. - Maintenez le processus de tunnel en cours pendant que Telegram fournit des mises à jour.
L'API Bot accepte les URL de webhook HTTPS. Telegram documente la prise en charge des webhooks sur les ports 443, 80, 88 et 8443 ; le point de terminaison public d'un tunnel géré utilise normalement 443 même lorsque le processus local transféré écoute sur 3000.
Enregistrez le webhook Telegram en toute sécurité
Créez un secret aléatoire contenant uniquement des lettres, des chiffres, des traits de soulignement ou des traits d'union. Le télégramme autorise 1 à 256 caractères. Ne réutilisez pas le jeton du bot avec cette valeur.
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 réduit le bruit et ne doit répertorier que les types de mises à jour gérés par le bot. drop_pending_updates=true est utile lors du démarrage d'une nouvelle session locale, mais il supprime définitivement les mises à jour en file d'attente, alors omettez-le lorsque ces événements sont importants. La Documentation de mise à jour de Telegram décrit des champs tels que message, callback_query et my_chat_member.
Confirmer l'enregistrement avant de déboguer le code
Utilisez getWebhookInfo pour séparer les échecs de configuration des échecs de gestionnaire :
curl -sS "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getWebhookInfo"
Vérifiez url, pending_update_count, last_error_message et last_error_date. Une URL vide signifie que l'inscription n'a pas été respectée. Un nombre croissant d'attentes signifie généralement que Telegram ne peut pas se connecter ou que votre point de terminaison renvoie un statut non-2xx. Envoyez un message direct au bot après l'inscription ; le simple fait d'ouvrir le chat ne crée pas nécessairement une mise à jour.
Gérer les mises à jour sans provoquer de nouvelles tentatives
Acquitter avant un travail lent
Renvoyer une réponse 2xx dès que la demande est authentifiée et durablement acceptée. Les exportations de bases de données, les appels IA et les API tierces doivent s'exécuter de manière asynchrone. Telegram réessaye les demandes infructueuses après des réponses non-2xx, donc un travail synchrone lent peut créer des doublons.
Dédupliquer avec update_id
Chaque mise à jour a un update_id. Stockez les identifiants traités avec une fenêtre d’expiration ou appliquez une clé de base de données unique. Une nouvelle tentative ne doit pas envoyer un deuxième reçu de paiement, créer un ticket en double ou exécuter le même rappel deux fois.
Modélisez explicitement chaque type de mise à jour
Toutes les mises à jour ne contiennent pas message.text. Les boutons de rappel arrivent sous callback_query ; Les publications sur la chaîne et les modifications d'adhésion ont d'autres champs. Branchez-vous sur le champ de niveau supérieur actuel et traitez les types inconnus comme des non-opérations valides plutôt que de les lancer.
Règles de sécurité pour les tests de robots Telegram locaux
- Validez d'abord l'en-tête secret. Rejetez les valeurs manquantes ou incorrectes avant de journaliser ou d'analyser les champs sensibles.
- Gardez les jetons hors des URL et des journaux. Le jeton de l'API Bot dans la commande d'enregistrement est un identifiant. Évitez l'historique du shell sur les systèmes partagés et faites pivoter un jeton exposé via BotFather.
- Utilisez un itinéraire indevinable et secret. L'itinéraire est une défense en profondeur ; l'en-tête secret est la vérification réelle de l'application.
- Limiter les données capturées. Les messages peuvent contenir des noms, des noms d'utilisateur, des numéros de téléphone, des fichiers et du texte de conversation privée. Rédigez les journaux et supprimez les captures locales une fois terminé.
- Ne désactivez jamais l'authentification en développement. Un tunnel public est public. Le code local doit exercer les mêmes contrôles que la production.
Voir le guide plus large de sécurité du tunnel localhost pour les pratiques de contrôle d'accès et de conservation des données.
Résoudre les échecs courants du webhook Telegram
Telegram signale une erreur de certificat ou de connexion
Utilisez l'URL HTTPS du tunnel, et non sa cible HTTP locale. Confirmez que le tunnel est actif et que l'URL n'a pas changé. Si vous fournissez plutôt votre propre certificat auto-signé, Telegram nécessite de télécharger le certificat public sous forme de fichier ; un point de terminaison TLS géré évite cette configuration.
Le point de terminaison renvoie 401
Comparez le secret transmis à setWebhook avec la variable d'environnement utilisée par le processus. Les noms d'en-tête ne sont pas sensibles à la casse, mais les proxys ou les middlewares peuvent supprimer les en-têtes personnalisés. Inspectez les en-têtes entrants sans imprimer la valeur secrète.
Aucune demande n'arrive
Exécutez getWebhookInfo, vérifiez que le chemin enregistré correspond exactement à votre itinéraire et assurez-vous qu'aucun pare-feu ne bloque la connexion locale du tunnel. Si vous avez récemment utilisé l'interrogation, confirmez que l'URL du webhook est désormais renseignée. Déclenchez une mise à jour réelle en envoyant un message au bot.
Les mises à jour arrivent à plusieurs reprises
État du journal et temps de réponse. Les exceptions après réception de la demande peuvent transformer un 200 prévu en 500. Renvoyez 200 rapidement, rendez le traitement idempotent et utilisez la relecture contrôlée du webhook plutôt que d'attendre les tentatives du fournisseur pendant le débogage.
Testez les requêtes et les fichiers de rappel, pas seulement le texte
Une matrice de test de robot utile couvre plus de message.text. Envoyez une photo avec une légende, partagez un contact, modifiez un message et appuyez sur un bouton du clavier en ligne. Pour les requêtes de rappel, appelez rapidement answerCallbackQuery afin que le client cesse d'afficher son indicateur de progression, puis effectuez un travail plus lent séparément. Les mises à jour de fichiers contiennent des identifiants ; le téléchargement des octets est une deuxième opération de l'API Bot et ne devrait pas retarder la réponse du webhook.
Conservez les appareils créés à partir de mises à jour nettoyées pour les tests unitaires, mais conservez le chemin de transport complet pour au moins un test de chaque type pris en charge. Un appareil prouve que votre répartiteur comprend une charge utile ; une véritable livraison tunnelisée prouve également le comportement d'enregistrement, de TLS, d'en-têtes, d'analyse du corps et d'accusé de réception. Lors de l'ajout d'une nouvelle entrée allowed_updates, appelez à nouveau setWebhook et vérifiez que getWebhookInfo reflète la configuration prévue.
Supprimer le webhook après la session locale
curl -sS -X POST \
"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/deleteWebhook" \
-d "drop_pending_updates=false"
La suppression du webhook vous permet de revenir à getUpdates. Si l'URL du tunnel change lors de la prochaine session, appelez à nouveau setWebhook. Pour des diagnostics supplémentaires, suivez le workflow général de débogage du webhook local .
