@vary_on_cookie由于非Django cookie而失败

时间:2014-04-28 16:34:36

标签: django caching

我在Django 1.5.6应用程序中遇到了一个缓存问题:

@vary_on_cookie
@cache_page(24 * 60 * 60, key_prefix=':1:community')
@rendered_with("general/community.html")
@allow_http("GET")
def community(request):
    ...
    return { ... }

本地缓存工作正常,但是当我在暂存中测试时,@ vary_on_cookie无效 - 我可以通过正在执行的查询看到社区() 正在后续执行调用此页面。

我在本地环境中更新了我的设置,使用相同的Redis缓存作为暂存来消除这种差异,但本地环境继续正常运行。

查看Redis在其缓存中的密钥,我可以看到问题所在 - 每次调用此页面时都会暂存,新密钥会添加到缓存中。比较cache.keys('*community*')的输出:

LOCAL:

首先调用社区页面:

[u'community:1:views.decorators.cache.cache_page.:1:community.GET.b528759dd79cf1c6b405290c0bc05e39.3b7d4c38ec8d92512a4a0847f4738298.en-us.America/New_York', 
u'community:1:views.decorators.cache.cache_header.:1:community.b528759dd79cf1c6b405290c0bc05e39.en-us.America/New_York']

第二次通话(同一用户):

[u'community:1:views.decorators.cache.cache_page.:1:community.GET.b528759dd79cf1c6b405290c0bc05e39.3b7d4c38ec8d92512a4a0847f4738298.en-us.America/New_York', 
u'community:1:views.decorators.cache.cache_header.:1:community.b528759dd79cf1c6b405290c0bc05e39.en-us.America/New_York']

请注意,两种情况下都有相同数量的密钥。

STAGING:

首先调用社区页面:

[u'community:1:views.decorators.cache.cache_header.:1:community.b528759dd79cf1c6b405290c0bc05e39.en-us.America/New_York',     
u'community:1:views.decorators.cache.cache_page.:1:community.GET.b528759dd79cf1c6b405290c0bc05e39.559380b85dc0cdcf0ff25051df78987d.en-us.America/New_York']

第二次通话(同一用户):

[u'community:1:views.decorators.cache.cache_header.:1:community.b528759dd79cf1c6b405290c0bc05e39.en-us.America/New_York', 
u'community:1:views.decorators.cache.cache_page.:1:community.GET.b528759dd79cf1c6b405290c0bc05e39.559380b85dc0cdcf0ff25051df78987d.en-us.America/New_York', 
u'community:1:views.decorators.cache.cache_page.:1:community.GET.b528759dd79cf1c6b405290c0bc05e39.6ec85abcc8a14d66800228bdccc537f0.en-us.America/New_York']

请注意,虽然它是同一个用户,但已在缓存中添加了一个额外的条目!

我很难过去哪里。这两种环境都使用SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'。登台环境清楚地认识到,这是其他所有用户。在@vary_on_cookie中发生了什么,这会在分段中产生差异,而不是在本地产生差异?

我已经检查了我的所有分段与本地差异,仔细检查了我的自定义中间件,但我对于要查看的内容没有任何想法。任何想法,即使是接下来看什么都将非常感激。谢谢!

更新

我检查了django.utils.cache._generate_cache_key(),看看它是如何生成缓存键的最后一个十六进制部分的。我天真地认为它只是看着Django自己的cookie(比如sessionid),但是我看到它使用传递到HTTP_COOKIE的cookie的全部 - 这意味着,Django和非Django。对我来说,这意味着来自Google Analytics和New Relic的Cookie,我都没有在本地运行。

for header in headerlist:  # headerlist = [u'HTTP_COOKIE']
        value = request.META.get(header, None) # the string of all cookies, for ex: __atuvc=39%7C17%2C8%7C18; csrftoken=dPqaXS6XVGp2UUvfhEW9kS6R6WPHQlE4; sessionid=j6a83wbsq1sez9bz75n0tzl4n884umg2'
        if value is not None:
            ctx.update(force_bytes(value))

真的可以这样吗?!使用@vary_on_cookie的所有世界Django网站都受到第三方cookie的阻挠?!

1 个答案:

答案 0 :(得分:1)

我创建了一个自定义装饰器,它会破坏HTTP标头以隔离用户的ID。 (虽然它在发送回浏览器的响应中设置Vary: DJANGO_USERID, Cookie,但它不包含实际ID。)

我很感激有关此解决方案的任何反馈,因为它超出了我的Django舒适区。谢谢!

def vary_on_user(view):
    """                                                                                                                                                                                                     
    Adapted from django.views.decorators.vary_on_cookie                                                                                                                                                                                          
    """
    @wraps(view, assigned=available_attrs(view))
    def inner_func(request, *args, **kwargs):
        request.META['HTTP_DJANGO_USERID'] = request.user.id
        response = view(request, *args, **kwargs)
        patch_vary_headers(response, ('DJANGO_USERID',))
        return response
    return inner_func