0%

telegram | 前后端 3种 交互案例

其主要的形式是,在机器人的聊天框中输入 /start/buy 可以使用 stars 支付。

关于前后端如何通信的请参考

后端

后端使用 python 编写,一共用了 3 种形式

  • 第三方 SDK
  • 轮训
  • webhook

后端通过调用 telegramsetWebhook 方法,来告诉 telegram 服务器,后台 ip 地址。

第三方 SDK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import logging
from telegram import Update, LabeledPrice
from telegram.ext import Application, CommandHandler, MessageHandler, filters, PreCheckoutQueryHandler, CallbackContext

# 设置机器人令牌
TOKEN = ""

logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)


async def start(update: Update, context: CallbackContext):
await update.message.reply_text("你好!选择 /buy 命令进行购买。")


async def buy(update: Update, context: CallbackContext):

chat_id = update.message.chat_id
title = "商品名称"
description = "商品描述"
payload = "Custom-Payload" # 自定义数据,用于验证支付
currency = "XTR" # 使用 Telegram Stars (XTR)
price = 5.00 # XTR 价格
prices = [LabeledPrice("商品名称", int(price * 100))] # 价格必须转换为整数,单位为货币最小单位

# 发送支付发票
await context.bot.send_invoice(
chat_id=chat_id,
title=title,
description=description,
payload=payload,
provider_token="", # 数字商品使用空 token
currency=currency,
prices=prices,
start_parameter="start_parameter" # 深度链接的起始参数
)


async def precheckout_callback(update: Update, context: CallbackContext):
query = update.pre_checkout_query
# 验证支付负载
if query.invoice_payload != 'Custom-Payload':
await query.answer(ok=False, error_message="出现错误...")
else:
await query.answer(ok=True)


async def successful_payment_callback(update: Update, context: CallbackContext):
payment = update.message.successful_payment
telegram_payment_charge_id = payment.telegram_payment_charge_id
# 发送支付成功确认消息
await update.message.reply_text(f"支付成功!您的ID:{telegram_payment_charge_id}")


def main():
# 创建应用实例
application = Application.builder().token(TOKEN).build()

# 添加命令处理器
application.add_handler(CommandHandler("start", start)) # 处理 /start 命令
application.add_handler(CommandHandler("buy", buy)) # 处理 /buy 命令

# 添加支付相关处理器
application.add_handler(PreCheckoutQueryHandler(precheckout_callback)) # 处理预结账查询
application.add_handler(MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment_callback)) # 处理支付成功消息

# 启动机器人
application.run_polling()


if __name__ == '__main__':
main()

这个第三方的原理也是轮训。

轮训

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import logging
import requests
import json
from typing import Dict, Any

# 设置机器人令牌
TOKEN = ""
BASE_URL = f"https://api.telegram.org/bot{TOKEN}"

# 配置日志记录
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)


def send_message(chat_id: int, text: str) -> Dict[str, Any]:
url = f"{BASE_URL}/sendMessage"
payload = {
"chat_id": chat_id,
"text": text
}
response = requests.post(url, json=payload)
return response.json()


def send_invoice(chat_id: int) -> Dict[str, Any]:
"""
发送支付发票
"""
url = f"{BASE_URL}/sendInvoice"
payload = {
"chat_id": chat_id,
"title": "商品名称",
"description": "商品描述",
"payload": "Custom-Payload",
"provider_token": "", # 数字商品使用空 token
"currency": "XTR", # 使用 Telegram Stars
"prices": [{"label": "商品名称", "amount": 500}], # 5.00 XTR (金额以分为单位)
"start_parameter": "start_parameter"
}
response = requests.post(url, json=payload)
return response.json()


def answer_pre_checkout_query(pre_checkout_query_id: str, ok: bool, error_message: str = None) -> Dict[str, Any]:
"""
响应预结账查询
"""
url = f"{BASE_URL}/answerPreCheckoutQuery"
payload = {
"pre_checkout_query_id": pre_checkout_query_id,
"ok": ok
}
if error_message and not ok:
payload["error_message"] = error_message

response = requests.post(url, json=payload)
return response.json()


def handle_update(update: Dict[str, Any]):
"""
处理更新消息
"""
try:
# 处理普通消息
if "message" in update:
message = update["message"]
chat_id = message["chat"]["id"]

# 处理文本消息和命令
if "text" in message:
text = message["text"]

if text == "/start":
send_message(chat_id, "你好!选择 /buy 命令进行购买。")
elif text == "/buy":
send_invoice(chat_id)

# 处理支付成功消息
if "successful_payment" in message:
payment = message["successful_payment"]
charge_id = payment["telegram_payment_charge_id"]
send_message(chat_id, f"支付成功!您的ID:{charge_id}")

# 处理预结账查询
elif "pre_checkout_query" in update:
query = update["pre_checkout_query"]
if query["invoice_payload"] == "Custom-Payload":
answer_pre_checkout_query(query["id"], True)
else:
answer_pre_checkout_query(query["id"], False, "出现错误...")

except Exception as e:
logger.error(f"处理更新时出错: {str(e)}")


def main():
"""
主函数 - 使用长轮询获取更新
"""
offset = None

while True:
try:
# 获取更新
params = {"timeout": 30}
if offset:
params["offset"] = offset

response = requests.get(f"{BASE_URL}/getUpdates", params=params)
updates = response.json()

if updates.get("ok") and updates.get("result"):
for update in updates["result"]:
handle_update(update)
# 更新 offset 为最后一个更新的 ID + 1
offset = update["update_id"] + 1

except Exception as e:
logger.error(f"主循环出错: {str(e)}")
continue


if __name__ == "__main__":
main()

webhook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import requests
from flask import Flask, request, jsonify

# 配置
TOKEN = "-poY"
BASE_URL = f"https://api.telegram.org/bot{TOKEN}"
WEBHOOK_PATH = "/webhook"

app = Flask(__name__)


def send_message(chat_id, text):
"""发送消息"""
url = f"{BASE_URL}/sendMessage"
payload = {
"chat_id": chat_id,
"text": text
}
requests.post(url, json=payload)


def send_invoice(chat_id):
"""发送支付发票"""
url = f"{BASE_URL}/sendInvoice"
payload = {
"chat_id": chat_id,
"title": "商品名称",
"description": "商品描述",
"payload": "Custom-Payload",
"provider_token": "", # 数字商品使用空 token
"currency": "XTR",
"prices": [{"label": "商品名称", "amount": 500}] # 5.00 XTR
}
requests.post(url, json=payload)


@app.route(WEBHOOK_PATH, methods=['POST'])
def handle_update():
"""处理 Telegram 发来的更新"""
update = request.get_json()
print(update)

if "message" in update:
message = update["message"]
chat_id = message["chat"]["id"]

if "text" in message:
text = message["text"]

if text == "/start":
send_message(chat_id, "你好!选择 /buy 命令进行购买。")
elif text == "/buy":
send_invoice(chat_id)

if "successful_payment" in message:
payment = message["successful_payment"]
charge_id = payment["telegram_payment_charge_id"]
send_message(chat_id, f"支付成功!您的ID:{charge_id}")

elif "pre_checkout_query" in update:
query = update["pre_checkout_query"]
url = f"{BASE_URL}/answerPreCheckoutQuery"
payload = {
"pre_checkout_query_id": query["id"],
"ok": query["invoice_payload"] == "Custom-Payload"
}
requests.post(url, json=payload)

return jsonify({"ok": True})


def setup_webhook():
"""设置 Webhook"""
# 1. 删除现有的 webhook
requests.post(f"{BASE_URL}/deleteWebhook")

# 2. 设置新的 webhook
webhook_url = "https://tgapi.thlm.bond/webhook"
set_url = f"{BASE_URL}/setWebhook"
set_payload = {
"url": webhook_url,
"allowed_updates": ["message", "pre_checkout_query", "callback_query"]
# "allowed_updates": []
}
response = requests.post(set_url, json=set_payload)
print("Webhook 设置结果:", response.json())

return response.json()


if __name__ == "__main__":
setup_webhook()
app.run(host='0.0.0.0', port=8443)

如果你成功和 telegram 设置后,你访问,这个地址 https://api.telegram.org/bot{TOKEN}/getWebhookInfo,就会发现你设置的信息。

我通过 nginx ,让 https://tgapi.thlm.bond 和 本地的 http://127.0.0.1:8443 进行连接。

请我喝杯咖啡吧~