Django緩存中間件解析。

前言

如果使用緩存中間件(在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屬于一個返回短路。
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 目錄 一、中間件簡介 在django中,中間件其實就是一個類,在請求到來和結束后,django會根據自己的規(guī)則在合...
    CaiGuangyin閱讀 884評論 0 3
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現,斷路器,智...
    卡卡羅2017閱讀 136,568評論 19 139
  • Refer to: www.threemeal.com/blog/12/ 中間件 中間件是一個鉤子框架,它們可以介...
    蘭山小亭閱讀 16,784評論 9 164
  • 中間件是一個鉤子框架,它們可以介入Django 的請求和響應處理過程。它是一個輕量級、底層的“插件”系統(tǒng),用于在全...
    低吟淺唱1990閱讀 586評論 0 0
  • Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606網站:h...
    布客飛龍閱讀 866評論 0 37

友情鏈接更多精彩內容