Telegram 的 WebApp 功能为机器人开发者打开了一扇新的大门:你可以创建交互式网页应用,并允许用户直接在聊天窗口中打开、操作并返回结果。本文将深入讲解如何通过机器人发送一个带有 WebApp 按钮的消息,以及如何处理用户从 WebApp 返回的数据(WebAppData),涵盖从配置到代码实现的全部细节。
WebApp 按钮与 WebAppData 基础
WebApp 按钮本质上是一个特殊的键盘按钮,其类型为 web_app,点击后会打开一个指定的 HTTPS 网页(WebApp)。用户在与 WebApp 交互后,可以调用 Telegram 提供的 JS SDK 中的 sendData() 方法,将数据传回机器人。此时,机器人会收到一条包含 web_app_data 字段的普通消息。
需要注意:WebApp 按钮只能通过内联键盘(InlineKeyboardButton)或回复键盘(ReplyKeyboardMarkup)发送,且必须同时指定一个有效的 URL。 此外,发送的内容必须符合 Telegram 的规范,比如 URL 必须是 HTTPS。WebApp 本身可以与机器人共享会话凭证,但这里我们专注于按钮的发送与数据接收。
在 BotFather 中配置 WebApp 地址
在发送 WebApp 按钮之前,需要先在 BotFather 中为你的机器人设置 WebApp 的主 URL(即 Mini App 根地址)。操作步骤如下:
- 打开 @BotFather,向你的机器人发送
/mybots,选择目标机器人。 - 点击 Bot Settings → WebApp → Set WebApp URL。
- 输入你的 WebApp 的 HTTPS 地址,例如
https://example.com/myapp。 - 保存后,即可在代码中使用该域名下的子路径作为按钮的 URL,但建议全路径指定。
注意:在开发阶段,你可以先设置一个占位 URL,但按钮中使用的 URL 必须与 BotFather 中配置的域名一致,否则可能无法打开。
发送 WebApp 按钮:内联键盘示例
下面以 Python 和 python-telegram-bot v20+ 为例,展示如何发送一个带有 WebApp 按钮的消息。其他语言或 HTTP API 实现逻辑相同。
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, MessageHandler, filters
# 机器人令牌和 WebApp URL
BOT_TOKEN = "YOUR_BOT_TOKEN"
WEBAPP_URL = "https://your-webapp.example.com"
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
# 创建 WebApp 内联按钮
keyboard = [
[InlineKeyboardButton(text="打开 WebApp", web_app=WebAppInfo(url=WEBAPP_URL))]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text("点下方按钮打开 WebApp:", reply_markup=reply_markup)
if __name__ == "__main__":
app = Application.builder().token(BOT_TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.run_polling()
要点:
InlineKeyboardButton的web_app参数接收一个WebAppInfo实例,其中必须包含有效的url。- 按钮文字可以自定义,但建议简洁明了。
- 除了内联键盘,你也可以使用
ReplyKeyboardMarkup,但通常内联按钮更自然。
处理 WebAppData 消息
当用户在 WebApp 中调用 Telegram.WebApp.sendData(data) 后,机器人会收到一条消息,其 web_app_data 字段中包含 data 字符串。以下代码演示如何接收并处理这条消息:
from telegram import Update, Message
from telegram.ext import MessageHandler, filters
async def web_app_data_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
message: Message = update.effective_message
if message.web_app_data:
data = message.web_app_data.data
user = update.effective_user
print(f"用户 {user.id} 发送了 WebApp 数据: ")
# 在这里做你的业务处理,例如解析 JSON、保存数据库等
await message.reply_text(f"收到数据:")
# 在 main 中添加处理器,注意必须使用 filters.StatusUpdate.WEB_APP_DATA 或根据消息类型过滤
app.add_handler(MessageHandler(filters.StatusUpdate.WEB_APP_DATA, web_app_data_handler))
注意:
filters.StatusUpdate.WEB_APP_DATA是 v20+ 中专门用于捕获 WebApp 数据更新的过滤器。你也可以使用filters.ALL并手动检查message.web_app_data。- WebApp 数据通常是字符串,可能是 JSON 格式,建议直接按业务需求解析。
验证 WebAppData 数据完整性
为了确保数据确实来自你的 WebApp(而不是恶意用户伪造),Telegram 会在发送的数据中附加一个哈希值。在 BotFather 中设置 WebApp 时,你可以添加一个密钥,并通过查询参数或 HTTP Header 传递。常用方法是将用户 ID 和随机生成的查询字符串传给 WebApp,WebApp 使用密钥对数据签名。但更标准的是使用 Telegram 提供的验证流程:
- 从 WebApp 获得的
initData通过Telegram.WebApp.initData获取。 - 验证顺序:计算哈希时,需要先将
initData按key=value对按 key 排序,并过滤掉hash字段。 - 使用 Bot 令牌作为密钥,HMAC-SHA256 进行哈希,并与
hash字段比较。
以下是一个简单的 Python 验证函数示例(基于社区标准实现):
import hashlib
import hmac
import json
from urllib.parse import urlencode
def verify_webapp_data(bot_token: str, init_data: str) -> bool:
data = dict(x.split("=", 1) for x in init_data.split("&"))
received_hash = data.pop("hash", "")
# 过滤空值,并按 key 排序
items = [(k, v) for k, v in data.items() if v != ""]
items.sort()
# 构造 secret_key 和 hash_data
secret_key = hmac.new(b"WebAppData", bot_token.encode(), hashlib.sha256).digest()
hash_data = urlencode(items)
calculated_hash = hmac.new(secret_key, hash_data.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(calculated_hash, received_hash)
强烈建议在生产环境中使用此验证,防止数据被篡改。
安全实践与常见问题
安全建议
- 始终使用 HTTPS 托管 WebApp,避免敏感信息明文传输。
- 在 WebApp 中避免保存用户凭证,尽量使用 Telegram 提供的用户信息。
- 对 WebAppData 中的内容做严格的输入验证,防止注入攻击。
- 定期轮换 Bot 令牌,并确保密钥不被泄露。
常见问题
- 按钮打开了但无法发送数据? 请检查 WebApp 是否引入了 Telegram WebApp JS SDK,并调用了
Telegram.WebApp.ready()和sendData()。 - 收不到 WebAppData 消息? 确认你的 bot 是通过内联按钮发送的,且用户点击后确实执行了
sendData。同时检查服务器日志,看是否被其他处理器拦截。 - 验证哈希不通过? 检查是否使用了正确的 bot token,以及 initData 是否完整。注意 initData 需要 URL 编码后发送,并使用原始字符串验证。
总结
通过 WebApp 按钮,Telegram 机器人可以突破纯聊天的限制,提供丰富的交互式界面。本文从按钮创建、发送到数据接收与验证,给出了完整的流程和代码。掌握这些技术后,你可以构建诸如投票、订单、表单收集、在线游戏等各种实用场景。记住,数据处理必须安全可靠,务必实现签名验证。现在,就为你的机器人添加一个 WebApp 按钮吧!