使用s3-boto中断浏览器缓存的django-storage

时间:2013-03-27 20:09:52

标签: django django-storage

我有一个django项目,在s3-boto上使用django-storage。

问题是位于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]

正如您所看到的,签名是不同的。我能做什么,不会破坏我的浏览器缓存?

6 个答案:

答案 0 :(得分:9)

在您的设置中,只需添加以下内容:

AWS_QUERYSTRING_AUTH = False

这将确保生成文件的URL而不使用额外的参数。您的网址如下:

https://my.s3.amazonaws.com/cache/user_6/profile_pic/profile_profile_picture_thumbnail.jpg

答案 1 :(得分:2)

您最好的选择是继承Boto S3存储后端并覆盖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'

只需确保您的图片可公开阅读。

答案 2 :(得分:0)

保护一些文件存储空间

您的大多数媒体上传 - 例如用户头像 - 您想要公开。但是,如果您有一些需要身份验证的媒体才能访问它 - 比如只有成员可以访问的PDF简历 - 那么您不希望S3BotoStorage的公共读取的默认S3 ACL。这里我们没有子类,因为我们可以传入一个实例而不是引用一个类。

首先删除设置中所有文件字段的保护并添加缓存控件

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

答案 3 :(得分:0)

AWS_QUERYSTRING_AUTH = True(这是默认设置)时,django会在每次获取网址时生成临时网址

如果您不想生成临时网址:

AWS_QUERYSTRING_AUTH = False添加到您的settings.py

如果您还想要一个临时网址:

临时网址的有效期为AWS_QUERYSTRING_EXPIRE秒(默认为3600)。所以我们可以缓存这个临时网址(只要我们不缓存它的时间超过它的有效时间)。这样 - 我们可以为后续页面请求返回相同的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

答案 4 :(得分:0)

如果您关心使用签名的URL,但仍要缓存它们直到它们过期,则只需使用django内置的caching

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

答案 5 :(得分:0)

在settings.py文件中添加此行将启用图像文件的缓存。

AWS_S3_OBJECT_PARAMETERS = {
        'CacheControl': 'max-age=86400',
    }