【问题标题】:How to cache view for all users in Django如何在 Django 中为所有用户缓存视图
【发布时间】:2020-05-22 11:07:57
【问题描述】:

我正在尝试将 AWS ElastiCache 的 Memcached 实例与 Django 项目一起使用。它似乎正在为用户缓存视图,但如果您在不同的 PC 上进入,它不会被缓存,直到从该 PC(或具有不同浏览器的同一 PC)调用。

我不确定我做错了什么。

在settings.py我有

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': os.environ.get('CACHE_LOCATION','127.0.0.1:11211'),
    }
}

MIDDLEWARE = [
    'core.middleware.DenyIndexMiddleware',
    'core.middleware.XForwardedForMiddleware',
    'core.middleware.PrimaryHostRedirectMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
    'masquerade.middleware.MasqueradeMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.contrib.sites.middleware.CurrentSiteMiddleware',
    'cms.middleware.user.CurrentUserMiddleware',
    'cms.middleware.page.CurrentPageMiddleware',
    'cms.middleware.toolbar.ToolbarMiddleware',
    'cms.middleware.language.LanguageCookieMiddleware',
    'cms.middleware.utils.ApphookReloadMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
]

然后我使用cache_page缓存了视图

path('<str:service_type>/<str:location>/', cache_page(60*60)(views.canonical_search), name="canonical-search"),

如何缓存站点,以便无论用户如何都可以缓存页面?

编辑 我注意到在使用用户登录时它永远不会缓存。

【问题讨论】:

  • 您好!所有用户的 URL 都相同吗?我怀疑是这样,但如果不是,那就是问题所在,因为缓存系统基于每个 URL 而不是基于每个视图进行缓存。
  • url 对所有用户都一样
  • 用户是指登录/匿名吗?您的 Web 服务器 (nginx/apache) 中是否有任何缓存策略?
  • @SebCorbin 我正在使用 ElasticBeanstalk,但我没有明确设置任何缓存。不知道ElasticBeanstalk有没有

标签: django


【解决方案1】:

注意Vary 标头,cache_page() 会将其考虑在内。

通常,某些中间件可能会添加Vary 标头,例如:

  • CsrfViewMiddleware 添加Cookie,
  • GZipMiddleware添加Accept-Encoding
  • LanguageCookieMiddleware可以加Accept-Language

意味着一旦您拥有不同的 Cookie(会话)、编码或语言,您的页面就会拥有不同版本的缓存。

对于您的情况,CsrfViewMiddleware 可能是问题所在,您可以将装饰器 @csrf_exempt 添加到您的视图中,以便在响应中不设置 Vary: Cookie 标头。

更多信息https://docs.djangoproject.com/en/3.0/topics/cache/#using-vary-headers

【讨论】:

  • 那么我建议你检查浏览器发送和接收的请求和响应,比较响应的Vary标头和浏览器发送的标头。
  • 两者中的Vary 标头都显示vary: Accept-Language,Cookie,X-Forwarded-Proto,Accept-Encoding,User-Agent 我不明白这是在告诉我什么
  • 所以是的,你有很多可能的变化,我建议你在你正在使用的中间件中搜索Vary 或Cookie 并尝试调试哪个中间件正在添加它。此外,User-Agent 肯定是缓存未命中的一个可能原因。
  • 一旦我发现哪一个发生了变化,我该怎么办?
  • 我如何告诉它不要改变标题?
【解决方案2】:

尽管Django 文档,您可以阅读以下内容: Django’s cache framework

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

如果需要在本地存储页面

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': 'c:/foo/bar',
    }
}

但是,我的建议是存储结果(数据库结果、资产等),就像@PVSK 在this thread 中显示的那样:

from django.core.cache import cache    
def sample(request):
        cached_data = cache.get_many(['query1', 'query2'])
        if cached_data:
            return render(request, 'sample.html', {'query1': cached_data['query1'], 'query2': cached_data['query2']})
        else:
            queryset1 = Model.objects.all()
            queryset2 = Model2.objects.all()
            cache.set_many({'query1': queryset1 , 'query2': queryset2 }, None)
            return render(request, 'sample.html', {'query1': queryset1 , 'query2': queryset2})

【讨论】:

    【解决方案3】:

    嗯,起初我想知道您是否遇到了一些缓存默认限制。您没有在 CACHE 后端定义中使用 OPTIONS,因此默认情况下缓存限制为 300 个条目。

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': os.environ.get('CACHE_LOCATION','127.0.0.1:11211'),
            'OPTIONS': {
                'MAX_ENTRIES': 1000
            }
    
        }
    }
    

    我们也遇到的下一个可能的问题是,cache_key 生成考虑了完整的 QUERY_STRING,因此(?param=bla)。但是您已经声明所有用户的 url 都是相同的。

    接下来,正如 SebCorbin 正确指出的那样,是潜在的Vary 问题。

    UpdateCacheMiddleware 永远不会缓存对无 cookie 请求的 cookie 设置响应。

        def process_response(self, request, response):
            #...
    
            # Don't cache responses that set a user-specific (and maybe security
            # sensitive) cookie in response to a cookie-less request.
            if not request.COOKIES and response.cookies and has_vary_header(response, 'Cookie'):
                return response
    
            # ...
    
    

    对于process_request,中间件的执行顺序是从上到下,对于process_response,是从下到上。

    我怀疑其中一个较低的中间件(或视图)正在设置 cookie,因此您可以通过将 'django.middleware.cache.UpdateCacheMiddleware' 移动到有问题的中间件下方来解决此问题,但如果您不这样做,您可能会失去功能也不要移动 LocaleMiddleware 之类的功能中间件。

    如果您的视图代码正在设置 cookie,则您需要切换到低级缓存 API 以缓存昂贵的操作(或将 cookie 逻辑移动到位于 UpdateCacheMiddleware 中间件之上的中间件中)。

    【讨论】:

      猜你喜欢
      • 2021-08-09
      • 2013-12-07
      • 2018-02-24
      • 2021-06-28
      • 2012-10-22
      • 2016-10-28
      • 2013-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多