python - 通过 Flask 和 BytesIO 显示来自 S3 的文件(图像)

标签 python flask boto3 bytesio

我正在尝试使用 Boto3 将文件从 AWS S3 直接提取到 BytesIO 对象中。这最终将用于操作下载的数据,但现在我只是尝试通过 Flask 将该文件直接提供给用户。据我了解,以下内容应该起作用,但不起作用。浏览器根本不显示任何内容(并且仅显示下载的几个字节的数据)。

(在本例中,我的示例文件是 png)

from flask import Flask, send_from_directory, abort, Response, send_file, make_response
import boto3, botocore
import os
import io

AWS_ACCESS_KEY = os.environ['AWS_ACCESS_KEY'].rstrip()
AWS_SECRET_KEY = os.environ['AWS_SECRET_KEY'].rstrip()
S3_BUCKET = "static1"
app = Flask(__name__, static_url_path='/tmp')

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    s3 = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY, aws_secret_access_key=AWS_SECRET_KEY,)
    file = io.BytesIO()
    metadata = s3.head_object(Bucket=S3_BUCKET, Key=path)
    conf = boto3.s3.transfer.TransferConfig(use_threads=False)
    s3.download_fileobj(S3_BUCKET, path, file)
    return send_file(file, mimetype=metadata['ContentType'])

if __name__ == '__main__':
     app.run(debug=True,port=3000,host='0.0.0.0')

如果我修改该核心例程以将 BytesIO 对象写入磁盘,然后将其读回到新的 BytesIO 对象中 - 它工作正常。如下:

def catch_all(path):
    s3 = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY, aws_secret_access_key=AWS_SECRET_KEY,)
    file = io.BytesIO()
    metadata = s3.head_object(Bucket=S3_BUCKET, Key=path)
    conf = boto3.s3.transfer.TransferConfig(use_threads=False)
    s3.download_fileobj(S3_BUCKET, path, file)
    print(file.getvalue())
    fh = open("/tmp/test1.png","wb")
    fh.write(file.getvalue())
    fh.close()
    fh = open("/tmp/test1.png","rb")
    f2 = io.BytesIO(fh.read())
    fh.close
    print(f2.getvalue())
    return send_file(f2, mimetype=metadata['ContentType'])

围绕这个问题转了几天,很明显我错过了一些东西,但我不确定是什么。该脚本正在 Python 3.8 docker 容器内运行,其中包含 boto3/flask/etc 的最新副本。

最佳答案

倒回您的 BytesIO 对象应该可以解决问题,在 send_file(...) 之前使用 file.seek(0)

郑重声明,我不确定您的 boto3/botocore 调用是否是“最佳实践”,请尝试我最终得到的用例:

from boto3.session import Session

session = Session(
    aws_access_key_id=KEY_ID, aws_secret_access_key=ACCESS_KEY, region_name=REGION_NAME
)
s3 = session.resource("s3")


@base_bp.route("/test-stuff")
def test_stuff():
    a_file = io.BytesIO()
    s3_object = s3.Object(BUCKET, PATH)
    s3_object.download_fileobj(a_file)
    a_file.seek(0)
    return send_file(a_file, mimetype=s3_object.content_type)

它在从磁盘读取文件时起作用,因为您使用文件的完整内容实例化了 BytesIO,因此它已正确实现并且仍处于“位置 0”。

关于python - 通过 Flask 和 BytesIO 显示来自 S3 的文件(图像),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59038662/

相关文章:

python - Jinja2 通过 dict 循环控制什么键 :value is used

python - 使用 Boto3 将文件上传到带有前缀的 S3 存储桶

python - DynamoDB查询FilterExpression多条件链接Python

python - 从 PKCS7 (signature&data) 中提取分离的 PKCS7 签名

python - Pandas 数据框按日期排序,然后分配字母 A-Z

python-2.7 - 用不同的值初始化不同的 Celery Worker

python - 如何测试自定义 Flask 错误页面?

amazon-s3 - 通过 boto3 将内存对象写入 S3

python - 递归函数计算是否 11 除以一个数

javascript - 多语言库的 python 位的文件布局和 setuptools 配置