大文件使用 Flask 和 S3 的首选方式

问题描述 投票:0回答:4

我知道这有点开放性,但是我很困惑使用什么策略/方法申请使用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 存储桶中的单个对象出现的文件怎么办?我觉得这可以作为解决方案的基础,而不是解决方案本身。

python rest amazon-s3 flask flask-restful
4个回答
2
投票

或者您可以使用 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)

您可以在此处找到完整的 API 操作列表和示例

安装 Minio-Py 库

$ pip install minio

希望有帮助。

免责声明:我为Minio

工作

0
投票
  1. Flask只能使用内存来保存所有的http请求体,所以没有我所知道的磁盘缓冲等功能。
  2. Nginx 上传模块是上传大文件的好方法。文件在这里
  3. 也可以使用html5、flash发送trunked文件数据,在Flask中处理数据,但是比较复杂。
  4. 尝试查看 s3 是否提供一次性令牌。

0
投票

使用我在上面发布的链接,我最终完成了以下操作。如果您认为这是一个好的解决方案,请告诉我

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))
.
.
.

0
投票

所以我在这里找到了一个选项来实际使用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 中读到他们在技术上没有被删除。如果有人想插话,我会洗耳恭听。谷歌搜索你可以中止多部分上传

© www.soinside.com 2019 - 2024. All rights reserved.