You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord Bot替换requests为aiohttp后无法复用已下载图片如何解决?

错误原因

你遇到的ValueError: I/O operation on closed file报错,核心原因是:aiohttp.FormData在发送包含BytesIO的请求时,会读取完流内全部内容,并且在请求结束后自动关闭该IO流,因此后续再尝试读取同一个image对象时就会触发已关闭的报错。

解决方案

最稳妥的方式是先存储下载得到的图片原始二进制数据,需要使用时再基于原始数据新建BytesIO对象,全程不需要重复下载图片:

import io
import aiohttp
import discord


async def post_image(url, user, nick):
    debug = client.get_channel(channels[1])

    async with aiohttp.ClientSession() as session:
        # 下载图片并存储原始二进制
        async with session.get(url) as response:
            image_raw = await response.read()

        # 构造POST请求参数
        data = aiohttp.FormData()
        # 注意这里字段名要和你原有requests逻辑的字段对应,原逻辑用的是image不是file
        data.add_field('image', io.BytesIO(image_raw), filename='blank.png')
        data.add_field('user', str(user))
        data.add_field('nick', str(nick))

        # 请求外部接口获取结果
        async with session.post(image_host, data=data) as info:
            result = await info.text()

        # 用原始二进制新建BytesIO发送到Discord
        await debug.send(result, file=discord.File(io.BytesIO(image_raw), 'blank.png'))

如果你不想多次创建BytesIO对象,也可以在POST请求结束后手动重置流指针,但该方法存在版本兼容风险(部分版本aiohttp会强制关闭流),仅作参考:

# 下载后创建BytesIO
image = io.BytesIO(await response.read())
# ... 构造FormData发送请求 ...
# 请求结束后重置指针到流开头
image.seek(0)
# 再发送到Discord
await debug.send(result, file=discord.File(image, 'blank.png'))

额外注意

你原有aiohttp代码里给FormData加的图片字段名是file,但你原先的requests逻辑里用的字段名是image,如果不修改字段名,会导致外部接口接收不到图片参数,返回异常结果。

内容的提问来源于stack exchange,提问作者Stevy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:12:01