如何在 aiohttp 中发回 image/file

How to send back image/file in aiohttp

我需要知道如何在 aiohttp 中发回图像。我编写了一个用于调整图像大小的服务器。我用了aiohttp.web.FileResponse但是它需要保存文件而且有点问题(很多文件需要保存在硬盘上)。

有什么办法可以灵活地做到(不保存文件)?可能来自图像字节之类的?我阅读了 aiohttp 文档,但没有做太多。

这是我尝试做的事情:

  1. 文件响应

这里我必须保存它以发送回响应

image = tasks.get(key)  # PIL.Image
image.save('im_server/pil_{}.jpg'.format(key))  
resp = web.FileResponse(f'im_server/pil_{key}.jpg')
return resp
  1. 流响应

当我使用此代码发出请求时,我得到了文件(正在上传到我的计算机上),但它不是图像。如果我尝试打开它作为图像,它说文件已损坏并且无法打开:(

image = tasks.get(key)  # PIL.Image
resp = web.StreamResponse(status=200)
resp.headers['Content-Type'] = 'Image/JPG'
await resp.prepare(request)
await resp.write(image.tobytes())
return resp

您可以使用 tempfile.SpooledTemporaryFile 来完成保存工作。它旨在将临时文件存储在内存中,并且只有在文件大小超过 max_size 参数时才会将文件保存在磁盘上。请注意,此参数默认为 0,因此您需要将其更改为合适的大小以避免将所有内容都存储在磁盘上。用法很简单,SpooledTemporaryFile 将 return 一个 file_like 对象句柄,你可以像普通文件一样写入它。一旦不需要它,只需关闭它,它就会自动从内存或磁盘中删除。更多用法可以参考文档:https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile.

您可以使用 io.BytesIO.

async def img_resize(req: web.Request):
    data = await req.post()
    url = data.get('url')
    width = data.get('width')
    height = data.get('height')

    if not all((url, width, height)):
        return web.HTTPNotFound()

    try:
        width = int(width)
        height = int(height)
    except ValueError:
        return web.HTTPError()

    async with ClientSession() as session:
        async with await session.get(url) as res:
            if res.status != 200:
                return web.HTTPNotFound()

            img_raw = await res.read()

    im = Image.open(BytesIO(img_raw))
    im = im.resize((width, height), Image.BICUBIC)

    stream = BytesIO()
    im.save(stream, "JPEG")

    return web.Response(body=stream.getvalue(), content_type='image/jpeg')