Telegram Bot API
🌐 中文

Telegram Bot Webhook 设置教程:用 setWebhook 配置 Webhook URL 和 secret_token

· 9 分钟阅读

Telegram Bot Webhook 是 Telegram(电报)机器人接收消息的推送方式:一有新的更新,Telegram 就主动向你指定的 HTTPS 地址发送 POST 请求,你的程序不必再反复调用 getUpdates。设置方法是调用 Telegram Bot API 的 setWebhook,传入公网可访问的 HTTPS url,并建议同时设置 secret_token。本文介绍 Webhook URL 的要求、setWebhook 参数、请求头校验代码、如何用 getWebhookInfo 排查问题,以及切回轮询和常见报错的处理方法。

Webhook 和 getUpdates 有什么区别

对比项getUpdates(长轮询)Webhook
工作方式你的程序主动拉取更新Telegram 把更新推送到你的 URL
网络要求能访问 api.telegram.org 即可,本地电脑也能运行需要公网可访问的 HTTPS 地址
适合场景开发调试、小型机器人正式部署、Serverless、更新量大的机器人

两种方式互斥:设置了 Webhook,getUpdates 就会返回 409 Conflict。无论用哪种方式,尚未取走的更新最多在服务器上保存 24 小时。Webhook 收到的数据与 getUpdates 返回的一样,都是 JSON 格式的 Update 对象,只是每个请求只携带一个更新。还没有机器人的话,请先阅读 创建 Telegram 机器人教程。

Telegram Bot Webhook URL 的要求

本地开发时,localhost 无法被 Telegram 访问。要么继续用 getUpdates 调试,要么借助隧道(内网穿透)工具把本地端口映射为公网 HTTPS 地址。

调用 Telegram Bot API setWebhook 设置 Webhook URL

setWebhook 的常用参数:

参数说明
url必填。接收更新的 HTTPS 地址;传空字符串表示删除 Webhook。
secret_token1–256 个字符,只能包含 A-Z、a-z、0-9、_ 和 -。设置后每个推送请求都会带上请求头 X-Telegram-Bot-Api-Secret-Token。
allowed_updates只接收指定类型的更新,如 ["message", "callback_query"]。不传则沿用上一次的设置;传空列表表示接收除 chat_member、message_reaction、message_reaction_count 之外的所有类型。
drop_pending_updates传 true 丢弃所有尚未推送的积压更新。
max_connections同时推送的最大 HTTPS 连接数,1–100,默认 40。服务器性能有限就调小,需要更高吞吐就调大。
certificate自签名证书的公钥文件,必须以文件形式上传(multipart/form-data)。
ip_address推送时使用的固定 IP 地址,不再通过 DNS 解析域名。

使用受信任 CA 签发的证书(例如 Let's Encrypt)时,一条 curl 命令即可完成设置:

curl -X POST "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://bot.example.com/tg-webhook",
    "secret_token": "Kq8_x2-ReplaceWithRandomString",
    "allowed_updates": ["message", "callback_query"],
    "drop_pending_updates": true,
    "max_connections": 40
  }'

设置成功时返回:

{"ok": true, "result": true, "description": "Webhook was set"}

使用自签名证书时,需要通过 multipart/form-data 上传公钥文件:

curl -F "url=https://bot.example.com:8443/tg-webhook" \
     -F "certificate=@public.pem" \
     -F "secret_token=Kq8_x2-ReplaceWithRandomString" \
     "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/setWebhook"

secret_token 可以用 openssl rand -hex 32 生成(64 个十六进制字符,符合字符集要求)。也可以在 Bot API Tester 的 setWebhook 中填写参数后直接执行。

用 getWebhookInfo 检查 Webhook 状态

curl "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/getWebhookInfo"
{
  "ok": true,
  "result": {
    "url": "https://bot.example.com/tg-webhook",
    "has_custom_certificate": false,
    "pending_update_count": 17,
    "last_error_date": 1793266200,
    "last_error_message": "Wrong response from the webhook: 500 Internal Server Error",
    "max_connections": 40,
    "allowed_updates": ["message", "callback_query"]
  }
}

在浏览器中也可以用 getWebhookInfo 随时查看这些字段。

在代码中校验 secret_token 请求头

Webhook URL 是公开的,任何人都可以向它发送伪造的“更新”。设置了 secret_token 后,Telegram 的每个请求都会带上 X-Telegram-Bot-Api-Secret-Token 请求头,处理程序应该先比对它,不一致就直接返回 403。Python(Flask)示例:

import hmac
import os

import requests
from flask import Flask, abort, request

TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
SECRET = os.environ["TELEGRAM_WEBHOOK_SECRET"]
API = f"https://api.telegram.org/bot{TOKEN}"

app = Flask(__name__)

@app.post("/tg-webhook")
def webhook():
    got = request.headers.get("X-Telegram-Bot-Api-Secret-Token", "")
    if not hmac.compare_digest(got.encode(), SECRET.encode()):
        abort(403)  # 不是来自 Telegram 的请求
    update = request.get_json(silent=True) or {}
    msg = update.get("message")
    if msg and "text" in msg:
        requests.post(f"{API}/sendMessage", json={
            "chat_id": msg["chat"]["id"],
            "text": "收到:" + msg["text"],
        }, timeout=10)
    return "", 200

Node.js(Express)示例。这里演示另一种写法:直接在 Webhook 的响应体中返回要调用的方法(method 字段),可以省掉一次 API 请求,但无法得知这次调用是否成功:

import express from "express";

const SECRET = process.env.TELEGRAM_WEBHOOK_SECRET;
const app = express();
app.use(express.json());

app.post("/tg-webhook", (req, res) => {
  if (req.get("X-Telegram-Bot-Api-Secret-Token") !== SECRET) {
    return res.sendStatus(403);
  }
  const msg = req.body.message;
  if (msg?.text) {
    return res.json({ method: "sendMessage", chat_id: msg.chat.id, text: "收到:" + msg.text });
  }
  res.sendStatus(200);
});

// 由 Nginx 等反向代理在 443 端口处理 HTTPS,再转发到本机 3000 端口
app.listen(3000);

尽快返回 2xx,避免重复推送

Telegram 只把 2xx 状态码视为推送成功。返回其他状态码或请求超时时,它会重试同一个更新,多次失败后才放弃,期间 pending_update_count 会不断增加。因此:

用 deleteWebhook 切回 getUpdates

curl "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/deleteWebhook?drop_pending_updates=true"

加上 drop_pending_updates=true 会同时清空积压的更新,想保留它们就去掉这个参数。用空字符串作为 url 调用 setWebhook 也能删除 Webhook。删除之后即可用 getUpdates 轮询,例如按 Telegram chat id 获取教程查看聊天 ID。

注意:在 Bot API Tester 中启动 getUpdates 长轮询时,工具会先自动调用 deleteWebhook(保留积压的更新)。如果你的正式机器人依赖 Webhook,测试结束后记得重新调用 setWebhook。

常见错误与排查

现象原因解决方法
setWebhook 返回 400,描述中包含 An HTTPS URL must be provided for webhookURL 不是 HTTPS,例如填了 http://localhost:5678/...换成公网 HTTPS 地址;本地开发改用 getUpdates 或隧道
setWebhook 返回与端口有关的 400 错误端口不是 443、80、88、8443改用支持的端口,或通过反向代理转发
getUpdates 返回 409 Conflict已经设置了 Webhook,二者不能同时使用调用 deleteWebhook
last_error_message 中出现 SSL 或证书相关错误证书链不完整、域名与证书不匹配、自签名证书没有上传补全中间证书;自签名证书用 certificate 参数上传
Wrong response from the webhook: ...,pending_update_count 持续增加处理程序返回了非 2xx:404(路径不对)、403(secret_token 不一致)、500(代码异常)等核对路径和 secret_token;修复异常并尽快返回 200
n8n 运行在 localhost,Telegram 触发器无法启用n8n 的 Telegram 触发器依赖 Webhook,而 Telegram 无法访问本地的 HTTP 地址先为 n8n 配置公网 HTTPS 地址(域名或隧道),再启用触发器

还要记住:一个机器人同一时间只能有一个接收更新的地方。Webhook 一旦被 n8n 等工具注册,你自己的轮询脚本就会遇到 409;反过来,你调用 deleteWebhook 也会让这些工具收不到消息。如果同一个场景需要多个程序各自接收消息,最好为它们分别创建机器人,并各自保管 Token(参见 Telegram Bot Token 获取与管理教程)。

常见问题

Telegram Webhook 支持哪些端口?

只支持 443、80、88 和 8443 四个端口,并且必须使用 HTTPS。使用非 443 端口时要把端口写进 URL,例如 https://bot.example.com:8443/tg-webhook。

Webhook 的 secret_token 有什么用?

设置后,Telegram 的每个推送请求都会在请求头 X-Telegram-Bot-Api-Secret-Token 中带上这个值,服务器比对一致才处理,可以防止伪造的请求。长度 1–256 个字符,只能使用 A-Z、a-z、0-9、_ 和 -。

如何删除 Telegram 机器人的 Webhook?

调用 deleteWebhook(加上 drop_pending_updates=true 可同时丢弃积压的更新),或者用空字符串作为 url 调用 setWebhook。删除后就可以重新使用 getUpdates。

Webhook 设置成功了,为什么收不到消息?

先调用 getWebhookInfo,查看 last_error_message 和 pending_update_count。常见原因有证书链不完整、URL 发生重定向(不支持重定向),以及服务器返回了非 2xx 状态码。

本地 localhost 能直接使用 Webhook 吗?

不能。Telegram 必须能从公网通过 HTTPS 访问你的地址。本地开发可以改用 getUpdates 长轮询,或者用隧道工具把本地端口映射成公网 HTTPS 地址。

Webhook 和 getUpdates 可以同时使用吗?

不可以,二者互斥。设置 Webhook 后再调用 getUpdates 会返回 409 Conflict,要切回轮询必须先调用 deleteWebhook。

Telegram 机器人教程:从零创建 Telegram 机器人并发送第一条消息

Telegram 机器人教程:在 @BotFather 中用 /newbot 创建机器人并获取 Token,用 getMe 验证,再通过 getUpdates 找到 chat_id,用 curl 和 Python 发出第一条消息,附常见问题排查。

Telegram Bot API 发送消息教程:sendMessage 参数、格式、按钮与错误处理

Telegram Bot API 发送消息中文教程:sendMessage 参数说明,curl、Python、JavaScript 示例,HTML 与 MarkdownV2 格式、内联按钮、群组和频道发送,以及 400、403、429 错误处理。

Telegram Bot Token 怎么获取:获取、查看、验证和撤销机器人 Token

Telegram Bot Token 怎么获取?用 @BotFather 的 /newbot 获取新 Token,在 /mybots 中查看已有 Token,用 getMe 检查是否有效,泄露后及时撤销,并配合 chat_id 接入 n8n 等工具。

Telegram chat id 获取教程:查看用户、群组、频道和话题的聊天 ID

Telegram chat id 获取教程:用 getUpdates 查看私聊、群组、超级群组、频道和论坛话题的聊天 ID,讲清负数和 -100 前缀的含义,并排查 result 为空、409 Conflict 等常见问题,附 Python 示例。