1. 程式人生 > >web本地客戶端快取圖片實現

web本地客戶端快取圖片實現

瀏覽器快取是提高使用者體驗和提升程式效能的一個很重要的途徑,通過瀏覽器的快取控制,可以對實時性要求不高的資料進行快取,可以減少甚至不需要再次對伺服器的請求就可以顯示資料。

本文將介紹如果通過HTTP協議中的header來控制瀏覽器的快取行為,建議大家在看的時候寫程式碼試驗下,這樣對這些header的理解會更深一點。

HTTP協議定義了四個可以用來控制瀏覽器快取的HTTP頭,它們是:

Last-Modified
Expires
Pragma: no-cache
Cache-Control

下面分別介紹HTTP/1.0和HTTP/1.1協議下的快取解決方法。

HTTP/1.0

在HTTP/1.0協議中,Last-Modified是控制快取的一個非常重要的HTTP頭。如果需要控制瀏覽器的快取,伺服器首先必須傳送一個 以UTC時間為值的Last-Modifeid頭,當第二次訪問這個頁面時,瀏覽器會發送一個If-Modified-Since頭給伺服器,讓伺服器判 斷是否有必要更新內容,這個If-Modified-Since頭的值就是上次訪問頁面時,瀏覽器傳送的Last-Modifeid頭的值。

Expires是HTTP/1.0中另外一個很重要的HTTP頭,它表示快取的存在時間,告訴客戶端瀏覽器在這個時間之前不對伺服器傳送請求,而直接使用瀏覽器的快取。

在HTTP/1.0中,可以使用Pragma: no-cache頭來告訴瀏覽器不要快取內容,它相當於HTTP/1.1中的Cache-Control:no-cache。

如果要使用HTTP/1.0協議來告訴客戶端(包括任何中介代理)是否要快取資料,可以使用以下程式碼,如果設定liftTime引數則告訴客戶端資料快取的生命期為lifeTime的值:

  1. function http_10_cache_headers($lifeTime = null){  
  2.     $gmtime = time();  
  3.     if ($lifeTime){  
  4.         $gmtime += $lifeTime;  
  5.     }else {  
  6.         header("Pragma: no-cache");  
  7.     }  
  8.     $gmtime = gmdate('D, d M Y H:i:s',$gmtime).' GMT';  
  9.     header("Last-Modified: $gmtime");  
  10.     header("Expires: $gmtime");  
  11. }  

HTTP/1.0協議的這種實現方式的缺點是,伺服器和客戶端的時間有可能是不同步的,這樣會造成快取的實現達不到預期效果。HTTP/1.1協議用Cache-Control頭解決了這個問題。

HTTP/1.1

Cache-Control響應頭的語法為:
Cache-Control = “Cache-Control” “:”; #快取響應指令

快取響應指令為一下幾個中的任意一個:

  1. public
  2. private
  3. no-cache
  4. no-store
  5. no-transform
  6. must-revalidate
  7. proxy-revalidate
  8. max-age=時間
  9. s-maxage=時間

詳細介紹一下這幾個指令的具體含義:

  1. public 指示響應資料可以被任何客戶端快取
  2. private 指示響應資料可以被非共享快取所快取。這表明響應的資料可以被髮送請求的瀏覽器快取,而不能被中介所快取
  3. no-cache 指示響應資料不能被任何接受響應的客戶端所快取
  4. no-store 指示所傳送的響應資料除了不能被快取,也不能存入磁碟。一般用於敏感資料,以免資料被複制。
  5. must-revalidate 指示所有的快取都必須重新驗證,在這個過程中,瀏覽器會發送一個If-Modified-Since頭。如果伺服器程式驗證得出當前的響應資料為最新的數 據,那麼伺服器應當返回一個304 Not Modified響應給客戶端,否則響應資料將再次被髮送到客戶端。
  6. proxy-revalidate 與must-revalidate相似,不同的是用來指示共享快取。
  7. max-age 資料經過max-age設定的秒數後就會失效,相當於HTTP/1.0中的Expires頭。如果在一次響應中同時設定了max-age和Expires,那麼max-age將具有較高的優先順序。
  8. s-maxage 與max-age相似,不同的是用來指示共享快取。

瞭解這些指令後就可以根據不同的需求來發送不同的HTTP頭。

根據響應的內容是否更改來確定是否傳送新的響應資料:

  1. function validate_cache_headers($my_modtime)  
  2. {  
  3.     $pretty_modtime = gmdate('D, d M Y H:i:s', $my_modtime) . ' GMT';  
  4.     if($_SERVER['IF_MODIFIED_SINCE'] == $gmt_mtime) {  
  5.         header("HTTP/1.1 304 Not Modified");  
  6.         exit;  
  7.     }  
  8.     else {  
  9.         header("Cache-Control: must-revalidate");  
  10.         header("Last-Modified: $pretty_modtime");  
  11.     }  
  12. }  

這個函式接受一個頁面最後修改的時間作為引數,將它與瀏覽器傳送的If-Modified-Since的時間比較,如果兩者相同,說明快取的資料版 本是最新的,就可以傳送一個304狀態碼給瀏覽器,讓它使用快取的資料;否則,傳送新的Last-Modified頭和設定必須驗證快取的資料版本的 Cache-Control頭。

如果想要讓響應資料被代理快取一分鐘,可以這麼做:

  1. function cache_novalidate($interval = 60)  
  2. {  
  3.     $now = time();  
  4.     $pretty_lmtime = gmdate('D, d M Y H:i:s', $now) . ' GMT';  
  5.     $pretty_extime = gmdate('D, d M Y H:i:s', $now + $interval) . 'GMT';  
  6.     // 向後相容HTTP/1.0  
  7.     header("Last Modified: $pretty_lmtime");  
  8.     header("Expires: $pretty_extime");  
  9.     // 支援HTTP/1.1  
  10.     header("Cache-Control: public,max-age=$interval");  
  11. }  

如果只想讓瀏覽器快取響應資料,可以這麼做:

  1. function cache_browser($interval = 60)  
  2. {  
  3.     $now = time();  
  4.     $pretty_lmtime = gmdate('D, d M Y H:i:s', $now) . ' GMT';  
  5.     $pretty_extime = gmdate('D, d M Y H:i:s', $now + $interval) . ' GMT';  
  6.     // 向後相容HTTP/1.0  
  7.     header("Last Modified: $pretty_lmtime");  
  8.     header("Expires: $pretty_extime");  
  9.     // 支援HTTP/1.1  
  10.     header("Cache-Control: private,max-age=$interval,s-maxage=0");  
  11. }  

如果要讓資料不被任何客戶端快取:

  1. function cache_none($interval = 60)  
  2. {  
  3.   // 向後相容HTTP/1.0  
  4.   header("Expires: 0");  
  5.   header("Pragma: no-cache");  
  6.   // 支援HTTP/1.1  
  7.   header("Cache-Control: no-cache,no-store,max-age=0,s-maxage=0,must-revalidate");  
  8. }  

當呼叫session_start()時,PHP會自動傳送一個no-cache類的頭來阻止快取資料,

要注意的是:
通過POST方法傳送的請求不能以如上所述的方式快取。