【问题标题】:django-storage with s3-boto break browser cachedjango-storage 与 s3-boto 打破浏览器缓存
【发布时间】:2023-03-28 07:16:01
【问题描述】:

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

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

【问题讨论】:

标签: django django-storage


【解决方案1】:

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

AWS_QUERYSTRING_AUTH = False

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

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

【讨论】:

  • 谢谢!但如果我想设置一些我的 URL 安全?我该怎么做?
  • @Nuno_147 :对不起,我在原始答案中犯了一个错误。它应该是 AWS_QUERYSTRING_AUTH = False。更新了答案以反映这一点。
  • @Nuno_147 :安全,您的意思是您只想为某些文件添加查询字符串 auth 吗?还是你的意思是https?
  • 删除查询字符串有什么安全隐患?
  • 将 auth 查询字符串添加到某些 url 但不是全部创建另一个存储实例并传递 kwarg attr querystring_auth=False。
【解决方案2】:

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

如果不想生成临时url:

AWS_QUERYSTRING_AUTH = False 添加到您的settings.py

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

临时 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(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

【讨论】:

  • 从第 13 行 key = hashlib.md5 .... 得到错误“unicode-objects must be encrypted before hashing”
  • 通过编辑解决它:key = hashlib.md5(f"CachedS3Boto3Storage_{name}".encode()).hexdigest()
【解决方案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

【讨论】:

    【解决方案4】:

    最好的办法是继承 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'
    

    只要确保你的图片是公开可读的。

    【讨论】:

      【解决方案5】:

      如果你关心使用签名的 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
      

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          猜你喜欢
          • 2018-09-02
          • 1970-01-01
          • 2022-01-15
          • 1970-01-01
          • 1970-01-01
          • 2011-05-12
          • 2014-02-23
          • 2015-02-15
          • 2020-02-26
          相关资源
          最近更新 更多