HTTP CACHE 中的ETAG,LAST_MODIFY,MAX-AGE實驗

用世界上最好的語言演示一下etag

<?php

// apache 服務器,若是您是nginx請自行配置讀取header等信息,同時下面會有nginx測試

$file = 'etag.txt';
$etag = md5_file($file);
$headers = apache_request_headers();

if (isset($headers['If-None-Match']) && trim($headers["If-None-Match"]) == $etag) {
    header("HTTP/1.1 304 Not Modified");
} else {
    $content = file_get_contents($file);
    header("Etag: $etag");
    echo $content;
}

第一次請求,服務器返回200.我分別列下請求頭【RequsetHeaders】和響應頭【ResponseHeaders】php

請求頭css

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Cache-Control:no-cache
Connection:keep-alive
Host:kache.com
Pragma:no-cache
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.

響應頭html

Request URL:http://kache.com/etag.php
Request Method:GET
Status Code:200 OK
Remote Address:127.0.0.1:80

Connection:Keep-Alive
Content-Type:text/html
Date:Tue, 07 Mar 2017 13:02:13 GMT
Etag:966aa4bd5183fd9358fd222647c5c6a3
Keep-Alive:timeout=5, max=99
Server:Apache/2.4.10 (Win32) OpenSSL/0.9.8zb mod_fcgid/2.3.9
Transfer-Encoding:chunked
X-Powered-By:PHP/5.4.33

須要注意第一次請求頭沒有If-None-Match:,注意第一次響應頭有Etag:這個標籤,注意第一次是200nginx


第二次請求git

請求頭:github

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Host:kache.com
If-None-Match:966aa4bd5183fd9358fd222647c5c6a3
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

響應頭:web

Request URL:http://kache.com/etag.php
Request Method:GET
Status Code:304 Not Modified
Remote Address:127.0.0.1:80

Connection:Keep-Alive
Date:Tue, 07 Mar 2017 13:02:16 GMT
Keep-Alive:timeout=5, max=98
Server:Apache/2.4.10 (Win32) OpenSSL/0.9.8zb mod_fcgid/2.3.9

須要注意第二次請求頭有If-None-Match:,注意第二次響應爲304apache


再用php語言演示一下Last-Modified

<?php
/**
 *If-Modified-Since[request] & Last-Modified [response]
 *減小網絡字節傳輸
 */
$headers = apache_request_headers();
$file = 'modified.txt';

if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) == filemtime($file))) {

    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($file)) . ' GMT', true, 304);

} else {
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($file)) . ' GMT', true, 200);

    $content = file_get_contents($file);
    echo $content;
}

If-Modified-Since[請求頭的] 和 Last-Modified [響應頭的]這一對關係的HADER頭我這裏就不貼了。稍後的ppt裏有比較詳細的說明vim


咱們經常使用的就是Last-Modified和Etag一塊兒來用,上php代碼

<?php

$file='etag_modify.txt';

$last_modified_time=filemtime($file);

$etag = md5_file($file);

$headers = apache_request_headers();


if (@strtotime($headers['If-Modified-Since']) == $last_modified_time ||
    @trim($headers['If-None-Match']) == $etag) {
  header('Content-Length: '.filesize($file));
    header("HTTP/1.1 304 Not Modified");

}else{

  header("Etag: $etag");
  header('Last-Modified: '.gmdate('D, d M Y H:i:s', $last_modified_time).' GMT', true, 200);
  header('Content-Length: '.filesize($file));
  $content=file_get_contents($file);
  echo $content;

}

這樣作的好處是雙重驗證,同時知足二者條件纔會緩存失效,彌補了modify的粒度最多爲秒的問題以及modify的打開關閉即更改時間的問題。固然etag也會有坑,不一樣物理機可能會致使相同文件不一樣結果(沒實驗過)瀏覽器


直接上NGINX配置示例

畢竟php作服務端水平有限,你們能夠參考 swoole framework OR workerman中對etag和modify的處理。

很少說,上NGINX配置段,爲了演示modify ,能夠在/etc/nginx/nginx.conf中把etag關閉

http {

        ##
        # Basic Settings
        ##
        etag  off;
        ...

關於其餘靜態文件緩存的設置

location ~* \.(?:css)$ {
  #expires 1y;
  add_header  Cache-Control max-age=5;
  add_header Cache-Control "public";
  add_header  Last-Modified "";
}

簡單對以上括號內代碼說明:

  1. expires 1y; 是http協議1.0寫法,1.1對應的是cache-contorl:max-age='';前者爲GMT絕對時間,後者爲相對時間。

  2. add_header Cache-Control max-age=5; 緩存5秒,若是沒有Last-Modified(即設置了 add_header Last-Modified "";) ,期間會一直直接請求服務器,服務器一直返回200,若是有設置Last-Modified,5秒後會請求一次服務器,5秒前會返回304.

簡單概括Last-Modified和max-age(expires)關係

  1. 若是設置了max-age=0,而沒有啓用modify,那麼不會緩存

  2. 若是單單啓用modify,而沒有max-age==0.也會緩存

  3. 若是啓用了modify,而且 max-age=0,那麼不會緩存

  4. 若是設置了max-age=1000,但沒有啓用modify ,不會緩存

再此說明上面配置致使的結果:5秒內若是文件有變化,那麼客戶端不會有任何感知。5秒後將會從新發起請求,獲得200響應。而後再緩存5秒【注意沒有開啓etag】


下面這個例子和上面同樣,是針對圖片等,緩存1一個月,即便服務端刪除了,1個月內也會正常顯示(除非ctrl+f5,或者服務端重啓了)public表明任何代理服務器均可以緩存,對應的爲private,只容許客戶端瀏覽器緩存。

location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
  expires 1M;
  add_header Cache-Control "public";
  add_header  Last-Modified "";
}

那須要有更改就更新,怎麼辦?

location ~* \.(?:css)$ {
  expires 1y;
 # add_header  Cache-Control max-age=5;
 # add_header Cache-Control "public";
 # add_header  Last-Modified "";
}

以上配置雖然過時時間是一年,可是服務端會返回Last-Modified,來確認,意思爲你就vim了一下xx.css,即便沒有作任何更改,瀏覽器也會從新發起請求。你要是沒改,那八成就一年後見了。

那我就不想緩存怎麼辦?

用cache-control:控制
用no-cahce【瀏覽器端等能夠緩存,可是沒有什麼卵用】
用no-store【瀏覽器端等不用緩存,不用費勁。每次都跟我服務端請求】
用must-revalidate,瀏覽器端別整沒用的,到期了就立刻跟我請求。麻溜的必須。防止的就是代理服務器等自做聰明,認爲沒有過時。

location ~* \.(?:js)$ {
  add_header  Cache-Control no-cache;
  add_header  Cache-Control must-revalidate;
}

測試代碼和PPT在這裏

相關文章
相關標籤/搜索