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的值:
- function http_10_cache_headers($lifeTime = null){
- $gmtime = time();
- if ($lifeTime){
- $gmtime += $lifeTime;
- }else {
- header("Pragma: no-cache");
- }
- $gmtime = gmdate('D, d M Y H:i:s',$gmtime).' GMT';
- header("Last-Modified: $gmtime");
- header("Expires: $gmtime");
- }
HTTP/1.0協議的這種實現方式的缺點是,伺服器和客戶端的時間有可能是不同步的,這樣會造成快取的實現達不到預期效果。HTTP/1.1協議用Cache-Control頭解決了這個問題。
HTTP/1.1
Cache-Control響應頭的語法為:
Cache-Control = “Cache-Control” “:”; #快取響應指令
快取響應指令為一下幾個中的任意一個:
- public
- private
- no-cache
- no-store
- no-transform
- must-revalidate
- proxy-revalidate
- max-age=時間
- s-maxage=時間
詳細介紹一下這幾個指令的具體含義:
- public 指示響應資料可以被任何客戶端快取
- private 指示響應資料可以被非共享快取所快取。這表明響應的資料可以被髮送請求的瀏覽器快取,而不能被中介所快取
- no-cache 指示響應資料不能被任何接受響應的客戶端所快取
- no-store 指示所傳送的響應資料除了不能被快取,也不能存入磁碟。一般用於敏感資料,以免資料被複制。
- must-revalidate 指示所有的快取都必須重新驗證,在這個過程中,瀏覽器會發送一個If-Modified-Since頭。如果伺服器程式驗證得出當前的響應資料為最新的數 據,那麼伺服器應當返回一個304 Not Modified響應給客戶端,否則響應資料將再次被髮送到客戶端。
- proxy-revalidate 與must-revalidate相似,不同的是用來指示共享快取。
- max-age 資料經過max-age設定的秒數後就會失效,相當於HTTP/1.0中的Expires頭。如果在一次響應中同時設定了max-age和Expires,那麼max-age將具有較高的優先順序。
- s-maxage 與max-age相似,不同的是用來指示共享快取。
瞭解這些指令後就可以根據不同的需求來發送不同的HTTP頭。
根據響應的內容是否更改來確定是否傳送新的響應資料:
- function validate_cache_headers($my_modtime)
- {
- $pretty_modtime = gmdate('D, d M Y H:i:s', $my_modtime) . ' GMT';
- if($_SERVER['IF_MODIFIED_SINCE'] == $gmt_mtime) {
- header("HTTP/1.1 304 Not Modified");
- exit;
- }
- else {
- header("Cache-Control: must-revalidate");
- header("Last-Modified: $pretty_modtime");
- }
- }
這個函式接受一個頁面最後修改的時間作為引數,將它與瀏覽器傳送的If-Modified-Since的時間比較,如果兩者相同,說明快取的資料版 本是最新的,就可以傳送一個304狀態碼給瀏覽器,讓它使用快取的資料;否則,傳送新的Last-Modified頭和設定必須驗證快取的資料版本的 Cache-Control頭。
如果想要讓響應資料被代理快取一分鐘,可以這麼做:
- function cache_novalidate($interval = 60)
- {
- $now = time();
- $pretty_lmtime = gmdate('D, d M Y H:i:s', $now) . ' GMT';
- $pretty_extime = gmdate('D, d M Y H:i:s', $now + $interval) . 'GMT';
- // 向後相容HTTP/1.0
- header("Last Modified: $pretty_lmtime");
- header("Expires: $pretty_extime");
- // 支援HTTP/1.1
- header("Cache-Control: public,max-age=$interval");
- }
如果只想讓瀏覽器快取響應資料,可以這麼做:
- function cache_browser($interval = 60)
- {
- $now = time();
- $pretty_lmtime = gmdate('D, d M Y H:i:s', $now) . ' GMT';
- $pretty_extime = gmdate('D, d M Y H:i:s', $now + $interval) . ' GMT';
- // 向後相容HTTP/1.0
- header("Last Modified: $pretty_lmtime");
- header("Expires: $pretty_extime");
- // 支援HTTP/1.1
- header("Cache-Control: private,max-age=$interval,s-maxage=0");
- }
如果要讓資料不被任何客戶端快取:
- function cache_none($interval = 60)
- {
- // 向後相容HTTP/1.0
- header("Expires: 0");
- header("Pragma: no-cache");
- // 支援HTTP/1.1
- header("Cache-Control: no-cache,no-store,max-age=0,s-maxage=0,must-revalidate");
- }
當呼叫session_start()時,PHP會自動傳送一個no-cache類的頭來阻止快取資料,
要注意的是:
通過POST方法傳送的請求不能以如上所述的方式快取。