使AJAX可緩存——基於flask


  主流瀏覽器都有緩存機制,主要基於HTTP協議定義的緩存策略。對於一定時間內不發生變動的文檔緩存起來,對於下次請求,就可以直接返回緩存的結果。使用緩存有以下好處:

1、減少冗余的數據傳輸,節省網絡流量成本
2、減少加載時間,客戶能夠快速加載頁面
3、減少對服務端的壓力,避免過載

  我們一般會為靜態文件,如圖片,腳本,樣式表等設置緩存,這樣客戶端在下次請求時可以減少不必要的網絡請求。實際上,我們可以把它用在所有組件上,包括Ajax響應,只要可以確認結果不經常變動,就可以使用緩存策略。

AJAX

  AJAX (Asynchronous JavaScript and XML)表示異步的javascript和XML,實際上,現在最著名的是JSON。Ajax可分為主動請求和被動請求。被動請求指為了將來使用而預先發起的,提前加載一些用戶可能用到的數據,來提高用戶體驗。主動請求,指基於用戶當前的操作而發起的請求。

  雖然AJAX是異步請求,但是對於主動請求,用戶任然需要等待響應。即便是被動請求可以讓用戶感受不到等待,但是仍然會有請求,產生流量,對服務端產生壓力。

HTTP緩存策略

  HTTP協議通過Header來控制緩存的,包括請求和響應,這里只講響應的緩存機制。響應緩存主要通過Expires頭和Cache-control頭來控制。下面按優先級由高到列出一些常見的緩存策略,:

  1. Cache-Control:no-store 不要緩存這個文檔
  2. Cache-Control:no-cache 保存文檔,但是需要與服務端再驗證才能使用
  3. Cache-control:max-age 緩存最長保存時間,單位是秒
  4. Expires:日期 根據日期判斷過期,由於客戶端和服務器日期可能不同步,不推薦使用

 

緩存過期檢測

  為了防止使用了過期的數據,必須要為緩存設置過期時間,當緩存過期時,需要向服務器請求新的數據。但實際上,雖然緩存過期了,但是服務器的數文檔並沒有變動,並不需要返回整個文檔。因此客戶端可以讓服務端在改變文檔的情況下才發送整個文檔。這種特殊請求就是有條件的請求。條件請求一般使用Last-Modified/If-Modified-Since 和 Etag/If-None-Match。

  Last-Modified表示文檔的最后修改日期,當緩存過期了,客戶端向服務器發送If-Modified-Since:Last-Modified的值進行條件請求,當服務端在這段時間沒有修改文檔,那么就返回不包含主體的304響應,否則就返回新的文檔。

   ETag 則是一個唯一文件標識符,每次文件修改后都會生成一個新的 ETag,因此也可以根據Etag的值來判斷文檔有沒有更新。和最后修改時間檢測類似。

  如果響應首部僅包含Last-Modified,就使用If-Modified-Since驗證,如果僅包含ETag,那么使用If-None-Match來驗證。如果兩者都提供了,那么客戶端就應該同時發送兩種驗證。

基於Flask的緩存響應

 

def make_cache_control_response(json_data):
    #json_data可能來自數據庫或者服務端緩存(如redis等),也可能是新生成的json數據
    resp = make_response()
    resp.headers['Content-Type'] = 'application/json'
    resp.cache_control.max_age = 600 #最長緩存600秒
    if json_data.get('from_cache'):  #來自服務端緩存
        del json_data['from_cache']
        last_modified = json_data.get('cache_time', 0)
        if last_modified:
            del json_data['cache_time']
            resp.last_modified = datetime.fromtimestamp(last_modified) #添加Last-Moditified頭
    if not resp.last_modified:
        resp.last_modified = datetime.now()

    if request.if_modified_since and request.if_modified_since >= resp.last_modified: #如果是條件請求,並且緩存未過期,返回304響應
        return resp, 304
    resp.data = json.dumps(json_data)
    return resp, 200

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM