Обслуживание статических файлов в Flask из частного хранилища AWS S3 - PullRequest
0 голосов
/ 15 сентября 2018

Я разрабатываю приложение Flask, работающее на Heroku, которое позволяет пользователям загружать изображения. В приложении есть страница, отображающая изображения пользователя в таблице.

В целях разработки я сохраняю загруженные файлы в эфемерную файловую систему Heroku, и все работает нормально: изображения загружаются и отображаются правильно (я использую последний метод, показанный здесь подразумевает использование send_from_directory ()). Теперь я переместил хранилище на S3 и пытаюсь адаптировать код. Я использую Boto3 для загрузки файлов в корзину: он работает нормально. Мои сомнения связаны с загрузкой, чтобы заполнить страницы пользователей их изображениями .

Как объяснено здесь , я мог бы установить файл как "открытый для чтения" и использовать 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 (я должен удалить изображения из файловой системы) .

Какой самый лучший / предпочтительный способ, также учитывая производительность? Большое спасибо

1 Ответ

0 голосов
/ 15 сентября 2018

Предпочтительный способ - просто создать предварительно подписанный 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 вместо записи его в файловую систему.

...