如何在aiogram的FSM流程中暂存用户照片并后续回传(不存磁盘)
解决aiogram中FSM暂存照片并后续回传的问题
核心思路是利用aiogram的FSMContext存储照片相关数据,完全无需写入本地磁盘。下面提供两种常用实现方案:
方案一:存储照片file_id(推荐)
Telegram Bot API支持直接通过file_id发送媒体,这种方式最轻量化,无需处理二进制数据,资源消耗最低。
接收照片的处理函数
@dp.message_handler(content_types=['photo'], state=UserState.photo) async def get_photo(message: types.Message, state: FSMContext): # 获取最高分辨率照片的file_id photo_file_id = message.photo[-1].file_id # 将file_id存入FSM状态 await state.update_data(photo_file_id=photo_file_id) # 可选:测试发送,验证存储成功 await bot.send_photo(message.chat.id, photo_file_id) await UserState.main_text.set()
后续步骤回传照片的处理函数
@dp.message_handler(state=UserState.main_text) async def process_main_text(message: types.Message, state: FSMContext): # 从FSM状态中取出照片file_id data = await state.get_data() photo_file_id = data.get('photo_file_id') # 回传照片给用户 if photo_file_id: await bot.send_photo(message.chat.id, photo_file_id) # 其他业务逻辑... await state.finish()
方案二:存储照片二进制数据(适合需本地处理的场景)
如果需要对照片进行裁剪、压缩等本地操作,可以将二进制数据存入内存对象,再存入FSM状态。
接收照片的处理函数
from io import BytesIO @dp.message_handler(content_types=['photo'], state=UserState.photo) async def get_photo(message: types.Message, state: FSMContext): # 获取照片的远程文件对象 photo_file = await bot.get_file(message.photo[-1].file_id) # 下载二进制数据到内存中的BytesIO对象 photo_bytes = BytesIO(await bot.download_file(photo_file.file_path)) # 将二进制数据转为bytes后存入FSM(BytesIO对象无法直接序列化) await state.update_data(photo_bytes=photo_bytes.getvalue()) # 可选:测试发送,注意重置文件指针到开头 photo_bytes.seek(0) await bot.send_photo(message.chat.id, photo_bytes) await UserState.main_text.set()
后续步骤回传照片的处理函数
from io import BytesIO @dp.message_handler(state=UserState.main_text) async def process_main_text(message: types.Message, state: FSMContext): data = await state.get_data() photo_bytes_data = data.get('photo_bytes') if photo_bytes_data: # 将bytes转回BytesIO对象用于发送 photo_bytes = BytesIO(photo_bytes_data) await bot.send_photo(message.chat.id, photo_bytes) # 其他业务逻辑... await state.finish()
注意事项
- 优先选择方案一,
file_id存储更高效,Telegram会缓存媒体文件,重复发送无需重新上传。 - 若使用二进制存储,需注意FSM存储的限制:用
MemoryStorage时数据存在内存,机器人重启会丢失;用Redis等持久化存储时,要确保序列化支持bytes类型。 - 使用
BytesIO对象发送时,必须调用seek(0)重置指针到开头,否则会因指针在末尾导致读取不到数据。
内容的提问来源于stack exchange,提问作者WinnieNotThePooh
相关产品推荐
相关产品推荐

