前言
如果使用緩存中間件(在settings里面加上設置)那么中間件將會基于URL對Django的頁面進行緩存。啟用緩存中間件的規(guī)范方法是設置“UpdateCacheMiddleware”作為你的第一件中間件,而且“FetchFromCacheMiddleware”作為最后的中間件。
就像下面一樣:
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
...
'django.middleware.cache.FetchFromCacheMiddleware'
]
這是違反直覺的,而違反直覺的原因在于:“UpdateCacheMiddleware” 需要運行最后的響應階段,處理中間件自下而上; “FetchFromCacheMiddleware” 需要在請求階段最后運行,自上而下處理中間件。
在緩存中間件中,還有一類簡單的中間件:“CacheMiddleware”可以用于一些簡單的站點。但是,如果有任何其他中間件需要影響緩存密鑰,那么您就可以需要 “UpdateCacheMiddleware” 和 “FetchFromCacheMiddleware”兩個中間件,而不是僅用CacheMiddleware一個中間件。這種情況在有“LocaleMiddleware”出現的情況下是尤為經常。
緩存中間件的工作任務:
- 只有狀態(tài)碼為200的GET或HEAD請求被高速緩存。
- 每個頁面存儲的秒數由響應(Response)的“緩存控制(Cache-Control)”頭部中的“max-age”部分設置的。如果“max-age”部分沒有的話,那么此項設置落到CACHE_MIDDLEWARE_SECONDS變量上。
- 這個中間件期望HEAD請求與相應的GET請求完全相同的響應頭?!疽姽ぷ魅蝿?。
- 發(fā)生異常故障時時,從process_request那返回原始請求的淺層拷貝?!靖嬖V了我們這個東西是直接短路process_request, 直接生成HTTPResponse對象,然后這個HTTPResponse對象就是從原始的返回請求那邊傳過來的淺拷貝】
- 頁面將根據請求頭中的內容緩存響應的“Vary”title。
- 該中間件還在響應對象上設置ETag,Last-Modified,Expires和Cache-Control頭部。
緩存的代碼解析:
中間件
- UpdateCacheMiddleware
- FetchFromCacheMiddleware
- CacheMiddleware(繼承上面兩個)
UpdateCacheMiddleware
def process_response(self, request, response):
"""Sets the cache, if needed."""
if not self._should_update_cache(request, response):
# We don't need to update the cache, just return.
return response
if response.streaming or response.status_code != 200:
return 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
# Try to get the timeout from the "max-age" section of the "Cache-
# Control" header before reverting to using the default cache_timeout
# length.
timeout = get_max_age(response)
if timeout is 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:
cache_key = learn_cache_key(request, response, 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
Hook點:process_response
內容:
- 檢查是否需要更新緩存:
- 方法,過期,cookie等
- 如果需要更新緩存,則
- 先獲取cookie_key。
- 如果要渲染:把httpresponse對象中的緩存加入渲染好的模板。
- 如果不要渲染:就直接吧HttpResponse對象加入緩存中。
- 返回HttpRespone對象。
FetchFromCacheMiddleware
def process_request(self, request):
"""
Checks whether the page is already cached and returns the cached
version if available.
"""
if request.method not in ('GET', 'HEAD'):
request._cache_update_cache = False
return None # Don't bother checking the cache.
# try and get the cached GET response
cache_key = get_cache_key(request, self.key_prefix, 'GET', cache=self.cache)
if cache_key is None:
request._cache_update_cache = True
return None # No cache information available, need to rebuild.
response = self.cache.get(cache_key)
# if it wasn't found and we are looking for a HEAD, try looking just for that
if response is None and request.method == 'HEAD':
cache_key = get_cache_key(request, self.key_prefix, 'HEAD', cache=self.cache)
response = self.cache.get(cache_key)
if response is None:
request._cache_update_cache = True
return None # No cache information available, need to rebuild.
# hit, return cached response
request._cache_update_cache = False
return response
源碼解析:
- Hook點在process_request階段。
- 請求剛處理進來,針對工作任務中的2要求驗證HEAD和GET方法。
- 通過請求,找到cache_key從而能通過cache_key找到cache的內容。
- 按照【緩存中間件的工作任務】中的要求2,進行response的構建
- 這里直接構建一個response屬于一個返回短路。