【问题标题】:Serve static files in Flask from private AWS S3 bucket从私有 AWS S3 存储桶在 Flask 中提供静态文件
【发布时间】:2019-02-19 21:59:35
【问题描述】:

我正在开发一个在 Heroku 上运行的 Flask 应用程序,它允许用户上传图像。该应用有一个在表格中显示用户图像的页面。

出于开发目的,我将上传的文件保存到 Heroku 的 ephemeral 文件系统,一切正常:图像已正确加载和显示(我使用显示的最后一种方法 here 暗示使用 send_from_directory( ))。现在我已将存储移至 S3 并尝试调整代码。我使用 boto3 将文件上传到存储桶:它工作正常。 我的疑问与下载以用他们的图像填充用户页面有关

正如here 解释的那样,我可以将文件设置为“公共读取”并使用 URL(我认为这是 Flask-S3 所做的),但我宁愿不让免费访问这些文件. 因此,我的解决方案尝试是将文件下载到 Heroku 的文件系统并再次使用 send_from_directory() 提供图像,如下所示:

app.py

@app.route('/download/<resource>')
def download_image(resource):
    """ resource: name of the file to download"""
    s3 = boto3.client('s3',
                      aws_access_key_id=current_app.config['S3_ACCESS_KEY'],
                      aws_secret_access_key=current_app.config['S3_SECRET_KEY'])

    s3.download_file(current_app.config['S3_BUCKET_NAME'],
                     resource,
                     os.path.join('tmp',
                                  resource))

    return send_from_directory('tmp',  # Heroku's filesystem
                               resource,
                               as_attachment=False)

然后,我在模板中生成图片的 URL,如下所示:

...
<img src="{{ url_for('app.download_image',
                     resource=resource) }}" height="120" width="120">
...

它可以工作,但由于某些原因,我认为这不是正确的方法:其中,我应该管理 Heroku 的文件系统以避免在 dynos 重新启动之间耗尽所有空间(我应该从文件系统中删除图像) .

同时考虑性能,哪种方式是最佳/首选方式? 非常感谢

【问题讨论】:

    标签: heroku amazon-s3 flask boto3 static-files


    【解决方案1】:

    首选方法是简单地为图像使用create a pre-signed URL,并返回到该 URL 的重定向。这使文件在 S3 中保持私有,但会生成一个临时的、有时间限制的 URL,可用于直接从 S3 下载文件。这将大大减少服务器上发生的工作量,以及服务器消耗的数据传输量。像这样的:

    @app.route('/download/<resource>')
    def download_image(resource):
        """ resource: name of the file to download"""
        s3 = boto3.client('s3',
                          aws_access_key_id=current_app.config['S3_ACCESS_KEY'],
                          aws_secret_access_key=current_app.config['S3_SECRET_KEY'])
    
        url = s3.generate_presigned_url('get_object', Params = {'Bucket': 'S3_BUCKET_NAME', 'Key': resource}, ExpiresIn = 100)
        return redirect(url, code=302)
    

    如果您不喜欢该解决方案,您至少应该考虑从 S3 流式传输文件内容,而不是将其写入文件系统。

    【讨论】:

    • 只想指出,这种方法可以绕过每个用户的安全控制,因为任何拥有该链接的人都可以在分配的时间窗口内访问该文件。
    猜你喜欢
    • 2021-02-16
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多