
本文介绍使用 aiogram 构建双用户协同流程的完整方案:当用户 a 启动会话后,系统生成唯一验证码;用户 b 输入该码即触发双向通知,并完成临时配对,全程依托 sqlite 实现轻量级状态管理。
本文介绍使用 aiogram 构建双用户协同流程的完整方案:当用户 a 启动会话后,系统生成唯一验证码;用户 b 输入该码即触发双向通知,并完成临时配对,全程依托 sqlite 实现轻量级状态管理。
在实际 Bot 开发中,常需支持「邀请-响应」类交互(如组队匹配、协作验证、双人游戏启动等)。Aiogram 本身不内置跨用户会话关联机制,因此需结合持久化存储实现状态跟踪。本文以「用户 A 发起配对 → 系统生成随机验证码 → 用户 B 输入验证码 → 双方即时获知配对成功」为典型场景,提供可落地的工程化实现。
核心设计思路
- 无状态 Bot + 有状态存储:Bot 保持无状态处理逻辑,所有配对关系、验证码、用户 ID 映射均存于 SQLite 数据库;
- 单表统一管理:避免动态建表(如原答案中 CREATE table {user1_id + user2_id}),因其易引发 SQL 注入、权限问题及维护困难;推荐使用一张固定结构的 pairing_requests 表;
- 验证码防重 & 限时有效(可选增强):虽基础需求未要求时效性,但生产环境建议添加 created_at 和 expires_at 字段,配合定时清理任务。
数据库表结构(推荐)
CREATE TABLE IF NOT EXISTS pairing_requests ( id INTEGER PRIMARY KEY AUTOINCREMENT, initiator_id INTEGER NOT NULL, -- 用户 A 的 Telegram ID code TEXT UNIQUE NOT NULL, -- 如 'loremipsum' status TEXT DEFAULT 'pending', -- 'pending' / 'matched' / 'expired' created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, matched_at TIMESTAMP NULL );
完整 Aiogram 3.x 实现示例(Python)
import random from aiogram import Router, F from aiogram.types import Message from aiogram.filters import Command import sqlite3 router = Router() DB_PATH = "pairing.db" # 初始化数据库 def init_db(): with sqlite3.connect(DB_PATH) as conn: conn.execute(""" CREATE TABLE IF NOT EXISTS pairing_requests ( id INTEGER PRIMARY KEY AUTOINCREMENT, initiator_id INTEGER NOT NULL, code TEXT UNIQUE NOT NULL, status TEXT DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, matched_at TIMESTAMP NULL ) """) init_db() # 预定义验证码词库(建议至少 100+ 项以降低碰撞概率) CODE_WORDS = ["loremipsum", "randomtext", "bluewhale", "quantumflux", "nebulaedge", "zeroday"] @router.message(Command("start")) async def cmd_start(message: Message): user_id = message.from_user.id code = random.choice(CODE_WORDS) # 记录配对请求 with sqlite3.connect(DB_PATH) as conn: conn.execute( "INSERT INTO pairing_requests (initiator_id, code) VALUES (?, ?)", (user_id, code) ) conn.commit() await message.answer( f"✅ 已创建配对请求!nn请让另一位用户向本 Bot 发送以下验证码:n<code>{code}</code>nn(发送后你将立即收到通知)", parse_mode="HTML" ) @router.message(F.text.in_(CODE_WORDS)) # 简单匹配(生产环境建议用 WHERE code=? 查询) async def handle_code(message: Message): code = message.text.strip() user_b_id = message.from_user.id with sqlite3.connect(DB_PATH) as conn: # 查找待匹配的请求(且未被使用) cursor = conn.execute( "SELECT initiator_id FROM pairing_requests " "WHERE code = ? AND status = 'pending'", (code,) ) row = cursor.fetchone() if not row: await message.answer("❌ 无效或已被使用的验证码。") return user_a_id = row[0] # 更新状态并记录匹配时间 conn.execute( "UPDATE pairing_requests SET status = 'matched', matched_at = CURRENT_TIMESTAMP " "WHERE code = ?", (code,) ) conn.commit() # 通知双方 await message.bot.send_message( user_a_id, f"? 成功配对!用户 <code>{user_b_id}</code> 已输入验证码 <code>{code}</code>。", parse_mode="HTML" ) await message.answer( f"✅ 验证码已确认!已通知用户 <code>{user_a_id}</code>。", parse_mode="HTML" )
关键注意事项
- ✅ 安全性:F.text.in_(CODE_WORDS) 仅适用于小规模词库且无用户自定义输入场景;若词库动态扩展或需更高鲁棒性,应改用参数化查询 WHERE code = ?;
- ✅ 并发安全:SQLite 在多数 Bot 场景下足够,但高并发时建议加 conn.execute(“BEGIN IMMEDIATE”) 避免竞态;
- ⚠️ 错误处理:示例省略了异常捕获,生产环境务必包裹 try/except sqlite3.Error;
- ? 避免硬编码:CODE_WORDS 应从配置文件或环境变量加载,便于热更新与多语言支持;
- ? 清理策略:可定期执行 delete FROM pairing_requests WHERE status = ‘pending’ AND created_at
通过以上结构化设计,你不仅能稳定支撑双用户配对逻辑,还可快速扩展为多用户邀请链、带身份校验的协作流程等更复杂场景。核心在于——用数据库做“记忆”,让 Bot 始终专注“响应”。