django-storage с s3-boto сломать кеш браузера

У меня есть проект django, который использует django-storage поверх s3-boto.

Проблема в том, что каждый файл, расположенный на S3, не может кэшироваться, потому что URL-адрес меняется при каждом вызове.

вот два вызова, сгенерированные django-storage:

https://my.s3.amazonaws.com/cache/user_6/profile_pic/profile_profile_picture_thumbnail.jpg?Signature=HlVSayUIJj6dMyk%2F4KBtFlz0uJs%3D&Expires=1364418058&AWSAccessKeyId=[awsaccesskey]     
https://my.s3.amazonaws.com/cache/user_6/profile_pic/profile_profile_picture_thumbnail.jpg?Signature=xh2VxKys0pkq7yHpbJmH000wkwg%3D&Expires=1364418110&AWSAccessKeyId=[awsaccesskey]

Как видите, подпись другая. Что я могу сделать, чтобы это не сломало кеш моего браузера?


person Nuno_147    schedule 27.03.2013    source источник


Ответы (6)


В настройках просто добавьте следующее:

AWS_QUERYSTRING_AUTH = False

Это гарантирует, что URL-адреса файлов будут генерироваться БЕЗ дополнительных параметров. Ваши URL-адреса будут выглядеть так:

https://my.s3.amazonaws.com/cache/user_6/profile_pic/profile_profile_picture_thumbnail.jpg
person Deepak Prakash    schedule 29.03.2013
comment
Спасибо ! но если я хотел бы установить некоторые из моих URL-адресов защищенными? как мне это сделать ? - person Nuno_147; 30.03.2013
comment
@ Nuno_147: Извините, я допустил ошибку в исходном ответе. Должно быть AWS_QUERYSTRING_AUTH = False. Обновлен ответ, чтобы отразить это. - person Deepak Prakash; 31.03.2013
comment
@Nuno_147 Nuno_147: Под безопасным вы имеете в виду, что хотите добавить аутентификацию строки запроса только для определенных файлов? Или ты имеешь в виду https? - person Deepak Prakash; 31.03.2013
comment
каковы последствия для безопасности удаления строки запроса? - person ecoe; 04.07.2015
comment
Чтобы добавить строку запроса аутентификации к некоторым URL-адресам, но не ко всем, создайте другой экземпляр хранилища и передайте kwarg attr querystring_auth=False. - person pawciobiel; 29.10.2015
comment
Целью подписи строки запроса является безопасный/частный доступ. Это решение делает все общедоступным. Если вам нужен частный доступ к файлам, вам нужно оставить это значение истинным и вместо этого кэшировать сгенерированный URL-адрес. - person ZG101; 30.08.2019

Когда AWS_QUERYSTRING_AUTH = True (по умолчанию), django будет генерировать временный URL-адрес каждый раз, когда мы получаем URL-адрес.

Если вы не хотите генерировать временный URL-адрес:

Добавьте AWS_QUERYSTRING_AUTH = False в свой settings.py

Если вам все еще нужен временный URL:

Временные URL будут действительны в течение AWS_QUERYSTRING_EXPIRE секунд (3600 по умолчанию). Таким образом, мы можем кэшировать этот временный URL (при условии, что он не будет кэшироваться дольше, чем он действителен). Таким образом, мы можем вернуть тот же URL-адрес для последующих запросов страниц, позволяя браузеру клиента получать данные из своего кеша.

settings.py

# We subclass the default storage engine to add some caching
DEFAULT_FILE_STORAGE = 'project.storage.CachedS3Boto3Storage'

проект/storage.py

import hashlib

from django.conf import settings
from django.core.cache import cache
from storages.backends.s3boto3 import S3Boto3Storage

class CachedS3Boto3Storage(S3Boto3Storage):
    """ adds caching for temporary urls """

    def url(self, name):
        # Add a prefix to avoid conflicts with any other apps
        key = hashlib.md5("CachedS3Boto3Storage_%s" % name).hexdigest()
        result = cache.get(key)
        if result:
            return result

        # No cached value exists, follow the usual logic
        result = super(CachedS3Boto3Storage, self).url(name)

        # Cache the result for 3/4 of the temp_url's lifetime.
        try:
            timeout = settings.AWS_QUERYSTRING_EXPIRE
        except:
            timeout = 3600
        timeout = int(timeout*.75)
        cache.set(key, result, timeout)

        return result
person Aaron    schedule 20.03.2017

Защитите часть файлового хранилища

Большинство ваших мультимедийных загрузок — например, пользовательские аватары — вы хотите сделать общедоступными. Но если у вас есть какие-либо носители, требующие аутентификации, прежде чем вы сможете получить к ним доступ — скажем, PDF-резюме, которые доступны только для участников, — тогда вам не нужен S3BotoStorage ACL S3 по умолчанию для публичного чтения. Здесь нам не нужно создавать подклассы, потому что мы можем передать экземпляр, а не ссылаться на класс.

так что сначала снимите защиту со всех полей файла в настройках и добавьте контроль кеша

AWS_HEADERS = {
    'Cache-Control': 'max-age=86400',
}

# By default don't protect s3 urls and handle that in the model
AWS_QUERYSTRING_AUTH = False

Затем сделайте поле файла, которое вам нужно, защищенным, чтобы использовать ваш собственный защищенный путь.

from django.db import models
import storages.backends.s3boto

protected_storage = storages.backends.s3boto.S3BotoStorage(
  acl='private',
  querystring_auth=True,
  querystring_expire=600, # 10 minutes, try to ensure people won't/can't share
)

class Profile(models.Model):
  resume = models.FileField(
    null=True,
    blank=True,
    help_text='PDF resume accessible only to members',
    storage=protected_storage,
  )

Но вам также нужно использовать свое обычное хранилище, когда вы находитесь в разработке, и вы обычно используете локальное хранилище, так что лично я сделал это так.

if settings.DEFAULT_FILE_STORAGE == 'django.core.files.storage.FileSystemStorage':
    protected_storage = FileSystemStorage()
    logger.debug('Using FileSystemStorage for resumes files')
else:
    protected_storage = S3BotoStorage(
        acl='private',
        querystring_auth=True,
        querystring_expire=86400,  # 24Hrs, expiration try to ensure people won't/can't share after 24Hrs
    )
    logger.debug('Using protected S3BotoStorage for resumes files')

Ссылка: https://tartarus.org/james/diary/2013/07/18/fun-with-django-storage-backends

person Dr Manhattan    schedule 11.07.2016

Лучше всего подклассифицировать серверную часть хранилища Boto S3 и переопределить метод URL.

/проект/корень/storage.py

from django.conf import settings
from storages.backends.s3boto import S3BotoStorage

class S3Storage(S3BotoStorage):

    def url(self, name):
        name = self._clean_name(name)
        return '{0}{1}'.format(settings.MEDIA_URL, name)

/проект/корень/settings.py

MEDIA_URL = 'https://my.s3.amazonaws.com/'
DEFAULT_FILE_STORAGE = 'project.storage.S3Storage'
AWS_ACCESS_KEY_ID = '*******'
AWS_SECRET_ACCESS_KEY = '********'
AWS_STORAGE_BUCKET_NAME = 'your-bucket'

Просто убедитесь, что ваши изображения общедоступны для чтения.

person krak3n    schedule 27.03.2013

Если вы заботитесь об использовании подписанных URL-адресов, но хотите кэшировать их до истечения срока их действия, просто используйте встроенный в django кэширование:

from django.core.cache import cache

class MyModel(models.Model):
    #using django-storages with AWS_QUERYSTRING_AUTH=True
    media = models.FileField()

    @property
    def url(self):
        """
        Return signed url, re-using cached value if not expired.
        """
        #Refresh url if within n seconds of expiry to give clients
        #time to retrieve content from bucket.
        #Make sure AWS_QUERYSTRING_EXPIRE is sufficiently larger than n
        n = 30
        time_to_expiry = settings.AWS_QUERYSTRING_EXPIRE - n

        #Create a unique key for this instance's url in the cache
        key = '{0}{1}'.format(self.__class__.__name__, self.pk)

        url = cache.get(key)
        if not url:
            url = self.media.url    #refresh url via django-storages
            cache.set(key, url, time_to_expiry)

        return url
person ZG101    schedule 30.08.2019

Добавление этой строки в ваш файл settings.py активирует кеширование файла изображения.

AWS_S3_OBJECT_PARAMETERS = {
        'CacheControl': 'max-age=86400',
    }
person Puttamarigowda M S    schedule 03.12.2020