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 източник
comment
Възможен дубликат на Защо S3 (използване с boto и django-storages) дава подписан url дори за публични файлове?   -  person pawciobiel    schedule 29.10.2015


Отговори (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 : Под защитено, имате предвид, че искате да добавите удостоверяване на низа на заявката само за определени файлове? Или имаш предвид 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
Целта на подписа на низа за заявка е за защитен/личен достъп. Това решение прави всичко публично. Ако искате частен достъп до файлове, трябва да оставите това true и вместо това да кеширате генерирания url. - person ZG101; 30.08.2019

Когато AWS_QUERYSTRING_AUTH = True (което е по подразбиране), django ще генерира временен URL адрес всеки път, когато извлечем URL адреса.

Ако не искате да генерирате временен URL адрес:

Добавете AWS_QUERYSTRING_AUTH = False към вашите настройки.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'

project/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 автобиографии, които са достъпни само за членове – тогава не искате стандартният S3 ACL на S3BotoStorage за публично четене. Тук не е нужно да правим подкласове, защото можем да предадем инстанция, вместо да препращаме към клас.

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

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

Но вие също трябва да използвате нормалното си хранилище, когато сте в Dev, и обикновено използвате локално хранилище, така че аз лично го направих така

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

REF: https://tartarus.org/james/diary/2013/07/18/fun-with-django-storage-backends

person Dr Manhattan    schedule 11.07.2016

Най-добрият ви залог е да подкласирате Boto S3 Storage Backend и да замените url метода.

/project/root/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)

/project/root/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 адреси, но все пак искате да ги кеширате, докато изтече срокът им, просто използвайте вградения кеширане:

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