gpt4 book ai didi

django - 子类化 Django UpdateCacheMiddleware 和 FetchFromCacheMiddleware 的技术

转载 作者:行者123 更新时间:2023-12-04 12:48:50 25 4
gpt4 key购买 nike

我用过UpdateCacheMiddlewareFetchFromCacheMiddleware MiddleWare 启用站点范围的匿名缓存以取得不同程度的成功。

最大的问题是中间件只缓存匿名用户的第一个请求。由于在第一个响应中设置了 session_id cookie,因此该匿名用户的后续请求不会因为标题上的 View 级别缓存不同而命中缓存。

我的网页在匿名用户之间没有显着差异,只要它们确实不同,我可以通过 Ajax 处理。因此,我决定尝试子类化 Django 的缓存中间件,以不再在 Header 上有所不同。相反,它因匿名用户和登录用户而异。因为我使用的是 Auth 后端,并且该处理程序发生在从缓存中获取之前,所以它似乎工作。

class AnonymousUpdateCacheMiddleware(UpdateCacheMiddleware):

def process_response(self, request, response):
"""
Sets the cache, if needed.
We are overriding it in order to change the behavior of learn_cache_key().
"""

if not self._should_update_cache(request, response):
# We don't need to update the cache, just return.
return response
if not response.status_code == 200:
return response

timeout = get_max_age(response)
if timeout == None:
timeout = self.cache_timeout
elif timeout == 0:
# max-age was set to 0, don't bother caching.
return response
patch_response_headers(response, timeout)
if timeout:
######### HERE IS WHERE IT REALLY GOES DOWN #######
cache_key = self.learn_cache_key(request, response, self.cache_timeout, self.key_prefix, cache=self.cache)
if hasattr(response, 'render') and callable(response.render):
response.add_post_render_callback(
lambda r: self.cache.set(cache_key, r, timeout)
)
else:
self.cache.set(cache_key, response, timeout)
return response

def learn_cache_key(self, request, response, timeout, key_prefix, cache=None):
"""_generate_cache_header_key() creates a key for the given request path, adjusted for locales.

With this key, a new cache key is set via _generate_cache_key() for the HttpResponse

The subsequent anonymous request to this path hits the FetchFromCacheMiddleware in the
request capturing phase, which then looks up the headerlist value cached here on the initial response.

FetchFromMiddleWare calcuates a cache_key based on the values of the listed headers using _generate_cache_key
and then looks for the response stored under that key. If the headers are the same as those
set here, there will be a cache hit and the cached HTTPResponse is returned.
"""

key_prefix = key_prefix or settings.CACHE_MIDDLEWARE_KEY_PREFIX
cache_timeout = self.cache_timeout or settings.CACHE_MIDDLEWARE_SECONDS
cache = cache or get_cache(settings.CACHE_MIDDLEWARE_ALIAS)

cache_key = _generate_cache_header_key(key_prefix, request)

# Django normally varies caching by headers so that authed/anonymous users do not see same pages
# This makes Google Analytics cookies break caching;
# It also means that different anonymous session_ids break caching, so only first anon request works
# In this subclass, we are ignoring headers and instead varying on authed vs. anonymous users
# Alternatively, we could also strip cookies potentially for the same outcome

# if response.has_header('Vary'):
# headerlist = ['HTTP_' + header.upper().replace('-', '_')
# for header in cc_delim_re.split(response['Vary'])]
# else:
headerlist = []

cache.set(cache_key, headerlist, cache_timeout)
return _generate_cache_key(request, request.method, headerlist, key_prefix)

负责从缓存中检索页面的 Fetcher 看起来像这样
class AnonymousFetchFromCacheMiddleware(FetchFromCacheMiddleware):

def process_request(self, request):
"""
Checks whether the page is already cached and returns the cached
version if available.
"""
if request.user.is_authenticated():
request._cache_update_cache = False
return None
else:
return super(SmarterFetchFromCacheMiddleware, self).process_request(request)
UpdateCacheMiddleware 被大量复制, 明显地。我想不出一个更好的钩子(Hook)来使这个更清洁。

这通常看起来是一个好方法吗?有什么明显的问题浮现在脑海中?

谢谢,

最佳答案

您可以通过暂时从 response['Vary'] 中删除不需要的变化字段来解决此问题。 :

from django.utils.cache import cc_delim_re

class AnonymousUpdateCacheMiddleware(UpdateCacheMiddleware):
def process_response(self, request, response):
vary = None
if not request.user.is_authenticated() and response.has_header('Vary'):
vary = response['Vary']
# only hide cookie here, add more as your usage
response['Vary'] = ', '.join(
filter(lambda v: v != 'cookie', cc_delim_re.split(vary))
response = super(AnonymousUpdateCacheMiddleware, self).process_response(request, response)
if vary is not None:
response['Vary'] = vary
return response

另外,设置 CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True在设置中以防止对经过身份验证的用户进行缓存。

关于django - 子类化 Django UpdateCacheMiddleware 和 FetchFromCacheMiddleware 的技术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10940592/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com