7

我有一个 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]

如您所见,签名不同。我该怎么做才不会破坏我的浏览器缓存?

4

6 回答 6

10

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

AWS_QUERYSTRING_AUTH = False

这将确保在没有额外参数的情况下生成文件的 URL。您的网址如下所示:

https://my.s3.amazonaws.com/cache/user_6/profile_pic/profile_profile_picture_thumbnail.jpg
于 2013-03-29T20:06:59.377 回答
6

AWS_QUERYSTRING_AUTH = True(这是默认值)时,django 会在我们每次获取 url时生成一个临时url。

如果您不想生成临时 url:

添加AWS_QUERYSTRING_AUTH = False到您的 settings.py

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

临时 url 将在AWS_QUERYSTRING_EXPIRE几秒钟内有效(默认为 3600)。所以我们可以缓存这个临时 url(只要我们不缓存它超过它的有效时间)。这样 - 我们可以为后续的页面请求返回相同的 url,允许客户端浏览器从它们的缓存中获取。

设置.py

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

项目/存储.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(f"CachedS3Boto3Storage_{name}".encode()).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
于 2017-03-20T19:14:16.973 回答
3

保护一些文件存储

您上传的大部分媒体(例如用户头像)都希望公开。但是,如果您有一些需要身份验证才能访问的媒体——比如只有会员可以访问的 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

于 2016-07-11T14:24:23.627 回答
1

您最好的选择是继承 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'

只要确保您的图像是公开可读的。

于 2013-03-27T20:27:10.170 回答
0

如果您关心使用签名的 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
于 2019-08-30T02:28:36.263 回答
0

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

AWS_S3_OBJECT_PARAMETERS = {
        'CacheControl': 'max-age=86400',
    }
于 2020-12-03T11:00:08.407 回答