我知道这有点开放性,但是我很困惑使用什么策略/方法申请使用Flask和boto3开发的大文件上传服务。对于较小的文件,一切都很好。但是当大小超过 100 MB 时,看到你们的想法真的很高兴
我的想法如下 -
a) 使用某种 AJAX 上传器将文件流式传输到 Flask 应用程序(我试图构建的只是一个使用 Flask-Restful 的 REST 接口。任何使用这些组件的示例,例如 Flask-Restful、boto3 和流式大文件都是欢迎。)。上传应用程序将成为(我相信)我们正在构建的微服务平台的一部分。我不知道 flask 应用程序前面是否会有 Nginx 代理,或者它会直接从 Kubernetes pod/服务提供服务。如果它是直接服务的,对于在 kubernetes 和/或 Flask 层中的大文件上传,我是否必须更改某些内容?
b) 使用直接 JS 上传器(如 http://www.plupload.com/)并将文件直接流式传输到 s3 存储桶中,完成后获取 URL 并将其传递给 Flask API 应用程序并将其存储在数据库中.问题是,凭据需要在 JS 的某个地方,这意味着安全威胁。 (不确定是否还有其他顾虑)
你认为其中哪一个(或者我根本没有考虑过的不同的东西)是最好的方法,我在哪里可以找到一些代码示例?
提前致谢。
[编辑]
我发现了这个 - http://blog.pelicandd.com/article/80/streaming-input-and-output-in-flask 作者正在处理像我这样的类似情况,他提出了一个解决方案.但是他正在打开一个已经存在于磁盘中的文件。如果我想直接上传作为 s3 存储桶中的单个对象出现的文件怎么办?我觉得这可以作为解决方案的基础,而不是解决方案本身。
或者您可以使用 Minio-py 客户端库,它是开源的并且与 S3 API 兼容。它本机为您处理分段上传。
一个简单的put_object.py例子:
import os
from minio import Minio
from minio.error import ResponseError
client = Minio('s3.amazonaws.com',
access_key='YOUR-ACCESSKEYID',
secret_key='YOUR-SECRETACCESSKEY')
# Put a file with default content-type.
try:
file_stat = os.stat('my-testfile')
file_data = open('my-testfile', 'rb')
client.put_object('my-bucketname', 'my-objectname', file_data, file_stat.st_size)
except ResponseError as err:
print(err)
# Put a file with 'application/csv'
try:
file_stat = os.stat('my-testfile.csv')
file_data = open('my-testfile.csv', 'rb')
client.put_object('my-bucketname', 'my-objectname', file_data,
file_stat.st_size, content_type='application/csv')
except ResponseError as err:
print(err)
安装 Minio-Py 库
$ pip install minio
希望有帮助。
免责声明:我为Minio
工作使用我在上面发布的链接,我最终完成了以下操作。如果您认为这是一个好的解决方案,请告诉我
import boto3
from flask import Flask, request
.
.
.
@app.route('/upload', methods=['POST'])
def upload():
s3 = boto3.resource('s3', aws_access_key_id="key", aws_secret_access_key='secret', region_name='us-east-1')
s3.Object('bucket-name','filename').put(Body=request.stream.read(CHUNK_SIZE))
.
.
.
所以我在这里找到了一个选项来实际使用boto3分段上传
这里是使用烧瓶的以下功能的示例。 (这是一个未经测试的例子,用来解释它是如何工作的,而不是用于生产或任何东西)
my_save_files = {}
@app.route('/upload/stream', methods=['GET', 'POST'])
def upload_stream():
if 'i' not in request.headers \
or 'len' not in request.headers:
return 'fail'
for fn in request.files:
index = int(request.headers['i'])
length = int(request.headers['len'])
if fn == '':
return 'fail'
if fn not in my_save_files:
my_save_files[fn] = {'parts': [], 'id': s3.create_muiltipart_upload(fn)}
file = request.files[fn]
s3.multi_upload_part(
fn,
my_save_files[fn]['id'],
my_save_files[fn]['parts'],
file.read(),
index + 1 # parts start at 1
)
if index == length - 1:
s3.complete_multi_part_upload(fn, my_save_files[fn]['id'], my_save_files[fn]['parts'])
return 'sucess'
return 'fail'
这里是示例代码,它使用 boto3 来处理 S3 的multipart upload
r3 = boto3.resource('s3')
c3 = boto3.client('s3')
def create_muiltipart_upload(key):
multipart_upload = c3.create_multipart_upload(
# ACL='public-read',
Bucket=bucket_name, # 'bucket_name',
# ContentType='video/mp4',
Key=key, # 'movie.mp4',
)
return multipart_upload['UploadId']
def multi_upload_part(key, upload_id, parts, piece, part_number):
uploadPart = r3.MultipartUploadPart(
bucket_name, key, upload_id, part_number
)
uploadPartResponse = uploadPart.upload(
Body=piece,
)
parts.append({
'PartNumber': part_number,
'ETag': uploadPartResponse['ETag']
})
def complete_multi_part_upload(key, upload_id, parts):
completeResult = c3.complete_multipart_upload(
Bucket=bucket_name, # 'multipart-using-boto',
Key=key,
MultipartUpload={
'Parts': parts
},
UploadId=upload_id,
)
return completeResult
基本用法:
# https://blog.filestack.com/tutorials/amazon-s3-multipart-uploads-python-tutorial/
def multi_part_upload(file_path, key):
parts = []
i = 1 # part numbers start at 1
upload_id = create_muiltipart_upload(key)
with open(file_path, 'rb') as f:
while True:
piece = f.read(524288) # 0.5 mb == 1024**2 / 2
if piece == b'':
break
multi_upload_part(key, upload_id, parts, piece, i)
i += 1
print(complete_multi_part_upload(key, upload_id, parts))
没有提到,我还没有做的事情是删除未完成的文件。因为我想我在 docs 中读到他们在技术上没有被删除。如果有人想插话,我会洗耳恭听。谷歌搜索你可以中止多部分上传