我正在尝试使用 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
对象应该可以解决问题,在 file.seek(0)
之前使用 send_file(...)
。
作为记录,我不确定您的 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/