Telegram机器人发送WebApp按钮并处理WebAppData

本文详细介绍Telegram机器人如何创建和发送WebApp按钮,以及如何安全地接收和验证用户通过WebApp提交的数据。包含完整的代码示例、配置步骤和常见问题。

阅读提示涉及账号和安全设置时,请边阅读边核对当前设备界面。

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 根地址)。操作步骤如下:

  1. 打开 @BotFather,向你的机器人发送 /mybots,选择目标机器人。
  2. 点击 Bot SettingsWebAppSet WebApp URL
  3. 输入你的 WebApp 的 HTTPS 地址,例如 https://example.com/myapp
  4. 保存后,即可在代码中使用该域名下的子路径作为按钮的 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()

要点:

  • InlineKeyboardButtonweb_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 提供的验证流程:

  1. 从 WebApp 获得的 initData 通过 Telegram.WebApp.initData 获取。
  2. 验证顺序:计算哈希时,需要先将 initDatakey=value 对按 key 排序,并过滤掉 hash 字段。
  3. 使用 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 按钮吧!

FAQ

下载与安装

常见问题

WebApp按钮和普通URL按钮有什么区别?

WebApp按钮(web_app)会打开一个内嵌的Telegram迷你应用,并且应用可以通过JS SDK与机器人通信,例如使用sendData()将数据传回机器人。而普通URL按钮只是用浏览器或内置浏览器打开一个链接,无法直接与机器人交互。

如何确保WebAppData来自我们自己的WebApp?

Telegram提供了数据验证机制:在BotFather中设置WebApp后,用户通过WebApp发送的数据会附带一个哈希值。你可以使用Bot令牌作为密钥,对initData进行HMAC-SHA256签名,并与收到的哈希对比,验证通过才认为是安全的数据。

WebAppData可以发送哪些类型的数据?

WebAppData的data字段是字符串,通常可以传输任意文本内容。实践中常用JSON格式来结构化传递对象、数字、数组等。发送时需调用Telegram.WebApp.sendData(<字符串>),数据会被编码到消息的web_app_data.data字段中。

如果没有BotFather设置WebApp URL,可以发送按钮吗?

不可以。在BotFather中设置WebApp URL是必须的,否则按钮点击后会提示无效。即使你手动在代码中写了URL,Telegram服务器也会校验域名的有效性。