代码之家  ›  专栏  ›  技术社区  ›  Libra

从私有AWS S3 bucket在Flask中提供静态文件

  •  2
  • Libra  · 技术社区  · 6 年前

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

    为了便于开发,我将上传的文件保存到Heroku的 ephemeral here .

    here ,我可以将文件设置为“public read”并使用URL(我想这就是 Flask-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'])
    
        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)
    

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

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

    考虑到性能,哪种方法是最好的/首选的? 谢谢

    1 回复  |  直到 6 年前
        1
  •  14
  •   Mark B    6 年前

    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流式传输文件内容,而不是将其写入文件系统。