深入PHP與瀏覽器緩存的分析
更新時(shí)間:2013年06月03日 17:14:12 作者:
本篇文章是對(duì)PHP與瀏覽器緩存進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
我們往往在服務(wù)器上對(duì)緩存設(shè)置進(jìn)行各種優(yōu)化方案,但是我們卻很少注意到客戶(hù)端緩存,準(zhǔn)確的說(shuō)是瀏覽器的緩存機(jī)制。
其實(shí)每種瀏覽器都有緩存策略,會(huì)暫時(shí)將每一個(gè)瀏覽過(guò)的文件緩存在一個(gè)特殊的文件夾里。我們就可以在用戶(hù)重復(fù)提交頁(yè)面請(qǐng)求的時(shí)候,告訴用戶(hù)這個(gè)頁(yè) 面沒(méi)有改變,可以調(diào)用緩存。 那我們?cè)趺粗烙脩?hù)有沒(méi)有這個(gè)頁(yè)面的緩存數(shù)據(jù)呢? 其實(shí)瀏覽器在發(fā)送請(qǐng)求的時(shí)候會(huì)先發(fā)送http頭,一般象這樣:
Date: Sun, 30 Jul 2006 09:18:11 GMT
Content-Type: image/gif
Last-Modified: Wed, 19 Jul 2006 07:40:06 GMT
ETag: "8c55da8d6abc61:2327"
Content-Length: 14757
其中
Last-Modified: Wed, 19 Jul 2006 07:40:06 GMT
ETag: "8c55da8d6abc61:2327"
就是有關(guān)頁(yè)面的緩存信息的。然后如果服務(wù)器返回的響應(yīng)代碼不是HTTP 200 (OK),而是 304的話(huà),瀏覽器就會(huì)從緩存中讀取數(shù)據(jù)。
//告訴客戶(hù)端瀏覽器不使用緩存,HTTP 1.1 協(xié)議
header("Cache-Control: no-cache, must-revalidate");
//告訴客戶(hù)端瀏覽器不使用緩存,兼容HTTP 1.0 協(xié)議
header("Pragma: no-cache");
根據(jù)這個(gè)原理,可以用在不經(jīng)常更新或者需要經(jīng)常刷新的頁(yè)面,可以大大減輕服務(wù)器的負(fù)擔(dān),因?yàn)樗绻l(fā)現(xiàn)客戶(hù)端有緩存,就向客戶(hù)端發(fā)送一個(gè)304響應(yīng),然后停止程序的執(zhí)行。
瀏覽器發(fā)出的請(qǐng)求中包含If-Modified-Since和If-None-Match 兩個(gè)參數(shù),第一個(gè)表示詢(xún)問(wèn)數(shù)據(jù)的最后修改時(shí)間是否是Thu,19 Jun 2008 16:24:01 GMT 然后服務(wù)器就會(huì)檢查數(shù)據(jù)的最后修改時(shí)間,如果是該時(shí)間則返回狀態(tài)碼304(表示沒(méi)有修改),此時(shí)當(dāng)瀏覽器收到狀態(tài)碼是304時(shí)就不會(huì)下載數(shù)據(jù)而是從本地緩 存中調(diào)用。然而只有本地緩存中存在著該請(qǐng)求資源的數(shù)據(jù)時(shí)瀏覽器才會(huì)發(fā)送If-Modified-Since參數(shù)并且其值為上一次服務(wù)器所返回的Last- Modified的值(并不是所有的服務(wù)器都支持If-Modified-Since和If-None-Match );If-None-Match的功能也類(lèi)似,它是由服務(wù)器返回的Etag的值生成的,可以是任意值,因?yàn)槠渥饔脙H僅是使服務(wù)器檢查數(shù)據(jù)的修改時(shí)間然后返 回而已,只要不為none(默認(rèn)值)或不為空其它的都可以。
所以我們可以在代碼的最前部分設(shè)置返回給瀏覽的Etag為某個(gè)值,然后在這個(gè)資源被第二次請(qǐng)求的時(shí)候就會(huì)附帶著一個(gè)If-None-Match 參 數(shù),通過(guò)核實(shí)其值確實(shí)為所發(fā)出的Etag值時(shí)就可以指定服務(wù)器返回為304然后強(qiáng)行退出程序就行了,If-Modified-Since也是一樣的做法這 里就只給出etag方法的php版(Last-Modified版的太常見(jiàn)了如設(shè)置緩存超時(shí)等等):
PHP 代碼復(fù)制到剪貼板
if ($_SERVER["HTTP_IF_NONE_MATCH"] == "claymorephp.com")
{
header('Etag:'.'zhaiyun.com',true,304);
exit();
}
else {
header('Etag:'."claymorephp.com");
}
你還可以稍微改一下:
$expires=date("Ymd"); //一天后緩存過(guò)期
if ($_SERVER["HTTP_IF_NONE_MATCH"] == $expires)
{
header('Etag:'.$expires,true,304);
exit();
}
else {
header('Etag:'.$expires);
}
if ($_SERVER["HTTP_IF_NONE_MATCH"] == "claymorephp.com") { header('Etag:'.'zhaiyun.com',true,304); exit(); } else { header('Etag:'."claymorephp.com"); } 你還可以稍微改一下: $expires=date("Ymd"); //一天后緩存過(guò)期 if ($_SERVER["HTTP_IF_NONE_MATCH"] == $expires) { header('Etag:'.$expires,true,304); exit(); } else { header('Etag:'.$expires); }
另外,當(dāng)GZIP和ETAG同時(shí)使用時(shí)有時(shí)會(huì)出問(wèn)題,就是ETAG沒(méi)有值,這個(gè)問(wèn)題是普遍存在的,我暫時(shí)沒(méi)有找到相關(guān)的原因,網(wǎng)上搜了一會(huì),普遍的人稱(chēng)之為BUG。
基于以上原因,關(guān)于PHPBLOG的客戶(hù)端緩存是以下來(lái)處理的(同時(shí)對(duì)HTTP_IF_NONE_MATCH和HTTP_IF_MODIFIED_SINCE進(jìn)行判斷):
PHP 代碼復(fù)制到剪貼板
if($_SERVER['HTTP_IF_NONE_MATCH'])
{
if($_SERVER['HTTP_IF_NONE_MATCH'] == 'phpblog')
{
header('Etag:phpblog',true,304);//控制瀏覽器緩存
$_SESSION['time_end']=microtime(true);
exit();
}
}
else if($_SERVER['HTTP_IF_MODIFIED_SINCE'])//eg:Sun, 02 Nov 2008 07:08:25 GMT; length=35849
{
$array=explode(' ',$_SERVER['HTTP_IF_MODIFIED_SINCE']);
$gmday=$array[1];
$month_array=array(
"Jan"=>"01",
"Feb"=>"02",
"Mar"=>"03",
"Apr"=>"04",
"May"=>"05",
"Jun"=>"06",
"Jul"=>"07",
"Aug"=>"08",
"Sep"=>"09",
"Oct"=>"10",
"Nov"=>"11",
"Dec"=>"12");
$gmmonth=$month_array[$array[2]];
$gmyear=$array[3];
$array=explode(':',$array[4]);
$gmtimestamp=gmmktime($array[0],$array[1],$array[2],$gmmonth,$gmday,$gmyear);
if(gmmktime()-$gmtimestamp<$config_client_cache_time*60*60)
{
header('Etag:phpblog',true,304);//控制瀏覽器緩存
$_SESSION['time_end']=microtime(true);
exit();
}
}
if($_SERVER['HTTP_IF_NONE_MATCH']) { if($_SERVER['HTTP_IF_NONE_MATCH'] == 'phpblog') { header('Etag:phpblog',true,304);//控制瀏覽器緩存 $_SESSION['time_end']=microtime(true); exit(); } } else if($_SERVER['HTTP_IF_MODIFIED_SINCE'])//eg:Sun, 02 Nov 2008 07:08:25 GMT; length=35849 { $array=explode(' ',$_SERVER['HTTP_IF_MODIFIED_SINCE']); $gmday=$array[1]; $month_array=array( "Jan"=>"01", "Feb"=>"02", "Mar"=>"03", "Apr"=>"04", "May"=>"05", "Jun"=>"06", "Jul"=>"07", "Aug"=>"08", "Sep"=>"09", "Oct"=>"10", "Nov"=>"11", "Dec"=>"12"); $gmmonth=$month_array[$array[2]]; $gmyear=$array[3]; $array=explode(':',$array[4]); $gmtimestamp=gmmktime($array[0],$array[1],$array[2],$gmmonth,$gmday,$gmyear); if(gmmktime()-$gmtimestamp<$config_client_cache_time*60*60) { header('Etag:phpblog',true,304);//控制瀏覽器緩存 $_SESSION['time_end']=microtime(true); exit(); } }
緩存的HEADER是這樣來(lái)發(fā)送的:
PHP 代碼復(fù)制到剪貼板
$client_cache_time=$config_client_cache_time*60*60;//單位 - 秒
header('Cache-Control: public, max-age='.$client_cache_time);
header('Expires: '.gmdate('D, d M Y H:i:s',time()+$client_cache_time).' GMT');//設(shè)置頁(yè)面緩存時(shí)間
header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');//返回最后修改時(shí)間
header('Pragma: public');
header('Etag:phpblog');//返回標(biāo)識(shí),用于標(biāo)識(shí)上次的確訪問(wèn)過(guò)(瀏覽器中存在緩存)
$client_cache_time=$config_client_cache_time*60*60;//單位 - 秒 header('Cache-Control: public, max-age='.$client_cache_time); header('Expires: '.gmdate('D, d M Y H:i:s',time()+$client_cache_time).' GMT');//設(shè)置頁(yè)面緩存時(shí)間 header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');//返回最后修改時(shí)間 header('Pragma: public'); header('Etag:phpblog');//返回標(biāo)識(shí),用于標(biāo)識(shí)上次的確訪問(wèn)過(guò)(瀏覽器中存在緩存)
其實(shí)每種瀏覽器都有緩存策略,會(huì)暫時(shí)將每一個(gè)瀏覽過(guò)的文件緩存在一個(gè)特殊的文件夾里。我們就可以在用戶(hù)重復(fù)提交頁(yè)面請(qǐng)求的時(shí)候,告訴用戶(hù)這個(gè)頁(yè) 面沒(méi)有改變,可以調(diào)用緩存。 那我們?cè)趺粗烙脩?hù)有沒(méi)有這個(gè)頁(yè)面的緩存數(shù)據(jù)呢? 其實(shí)瀏覽器在發(fā)送請(qǐng)求的時(shí)候會(huì)先發(fā)送http頭,一般象這樣:
Date: Sun, 30 Jul 2006 09:18:11 GMT
Content-Type: image/gif
Last-Modified: Wed, 19 Jul 2006 07:40:06 GMT
ETag: "8c55da8d6abc61:2327"
Content-Length: 14757
其中
Last-Modified: Wed, 19 Jul 2006 07:40:06 GMT
ETag: "8c55da8d6abc61:2327"
就是有關(guān)頁(yè)面的緩存信息的。然后如果服務(wù)器返回的響應(yīng)代碼不是HTTP 200 (OK),而是 304的話(huà),瀏覽器就會(huì)從緩存中讀取數(shù)據(jù)。
//告訴客戶(hù)端瀏覽器不使用緩存,HTTP 1.1 協(xié)議
header("Cache-Control: no-cache, must-revalidate");
//告訴客戶(hù)端瀏覽器不使用緩存,兼容HTTP 1.0 協(xié)議
header("Pragma: no-cache");
根據(jù)這個(gè)原理,可以用在不經(jīng)常更新或者需要經(jīng)常刷新的頁(yè)面,可以大大減輕服務(wù)器的負(fù)擔(dān),因?yàn)樗绻l(fā)現(xiàn)客戶(hù)端有緩存,就向客戶(hù)端發(fā)送一個(gè)304響應(yīng),然后停止程序的執(zhí)行。
瀏覽器發(fā)出的請(qǐng)求中包含If-Modified-Since和If-None-Match 兩個(gè)參數(shù),第一個(gè)表示詢(xún)問(wèn)數(shù)據(jù)的最后修改時(shí)間是否是Thu,19 Jun 2008 16:24:01 GMT 然后服務(wù)器就會(huì)檢查數(shù)據(jù)的最后修改時(shí)間,如果是該時(shí)間則返回狀態(tài)碼304(表示沒(méi)有修改),此時(shí)當(dāng)瀏覽器收到狀態(tài)碼是304時(shí)就不會(huì)下載數(shù)據(jù)而是從本地緩 存中調(diào)用。然而只有本地緩存中存在著該請(qǐng)求資源的數(shù)據(jù)時(shí)瀏覽器才會(huì)發(fā)送If-Modified-Since參數(shù)并且其值為上一次服務(wù)器所返回的Last- Modified的值(并不是所有的服務(wù)器都支持If-Modified-Since和If-None-Match );If-None-Match的功能也類(lèi)似,它是由服務(wù)器返回的Etag的值生成的,可以是任意值,因?yàn)槠渥饔脙H僅是使服務(wù)器檢查數(shù)據(jù)的修改時(shí)間然后返 回而已,只要不為none(默認(rèn)值)或不為空其它的都可以。
所以我們可以在代碼的最前部分設(shè)置返回給瀏覽的Etag為某個(gè)值,然后在這個(gè)資源被第二次請(qǐng)求的時(shí)候就會(huì)附帶著一個(gè)If-None-Match 參 數(shù),通過(guò)核實(shí)其值確實(shí)為所發(fā)出的Etag值時(shí)就可以指定服務(wù)器返回為304然后強(qiáng)行退出程序就行了,If-Modified-Since也是一樣的做法這 里就只給出etag方法的php版(Last-Modified版的太常見(jiàn)了如設(shè)置緩存超時(shí)等等):
PHP 代碼復(fù)制到剪貼板
復(fù)制代碼 代碼如下:
if ($_SERVER["HTTP_IF_NONE_MATCH"] == "claymorephp.com")
{
header('Etag:'.'zhaiyun.com',true,304);
exit();
}
else {
header('Etag:'."claymorephp.com");
}
你還可以稍微改一下:
$expires=date("Ymd"); //一天后緩存過(guò)期
if ($_SERVER["HTTP_IF_NONE_MATCH"] == $expires)
{
header('Etag:'.$expires,true,304);
exit();
}
else {
header('Etag:'.$expires);
}
if ($_SERVER["HTTP_IF_NONE_MATCH"] == "claymorephp.com") { header('Etag:'.'zhaiyun.com',true,304); exit(); } else { header('Etag:'."claymorephp.com"); } 你還可以稍微改一下: $expires=date("Ymd"); //一天后緩存過(guò)期 if ($_SERVER["HTTP_IF_NONE_MATCH"] == $expires) { header('Etag:'.$expires,true,304); exit(); } else { header('Etag:'.$expires); }
另外,當(dāng)GZIP和ETAG同時(shí)使用時(shí)有時(shí)會(huì)出問(wèn)題,就是ETAG沒(méi)有值,這個(gè)問(wèn)題是普遍存在的,我暫時(shí)沒(méi)有找到相關(guān)的原因,網(wǎng)上搜了一會(huì),普遍的人稱(chēng)之為BUG。
基于以上原因,關(guān)于PHPBLOG的客戶(hù)端緩存是以下來(lái)處理的(同時(shí)對(duì)HTTP_IF_NONE_MATCH和HTTP_IF_MODIFIED_SINCE進(jìn)行判斷):
PHP 代碼復(fù)制到剪貼板
復(fù)制代碼 代碼如下:
if($_SERVER['HTTP_IF_NONE_MATCH'])
{
if($_SERVER['HTTP_IF_NONE_MATCH'] == 'phpblog')
{
header('Etag:phpblog',true,304);//控制瀏覽器緩存
$_SESSION['time_end']=microtime(true);
exit();
}
}
else if($_SERVER['HTTP_IF_MODIFIED_SINCE'])//eg:Sun, 02 Nov 2008 07:08:25 GMT; length=35849
{
$array=explode(' ',$_SERVER['HTTP_IF_MODIFIED_SINCE']);
$gmday=$array[1];
$month_array=array(
"Jan"=>"01",
"Feb"=>"02",
"Mar"=>"03",
"Apr"=>"04",
"May"=>"05",
"Jun"=>"06",
"Jul"=>"07",
"Aug"=>"08",
"Sep"=>"09",
"Oct"=>"10",
"Nov"=>"11",
"Dec"=>"12");
$gmmonth=$month_array[$array[2]];
$gmyear=$array[3];
$array=explode(':',$array[4]);
$gmtimestamp=gmmktime($array[0],$array[1],$array[2],$gmmonth,$gmday,$gmyear);
if(gmmktime()-$gmtimestamp<$config_client_cache_time*60*60)
{
header('Etag:phpblog',true,304);//控制瀏覽器緩存
$_SESSION['time_end']=microtime(true);
exit();
}
}
if($_SERVER['HTTP_IF_NONE_MATCH']) { if($_SERVER['HTTP_IF_NONE_MATCH'] == 'phpblog') { header('Etag:phpblog',true,304);//控制瀏覽器緩存 $_SESSION['time_end']=microtime(true); exit(); } } else if($_SERVER['HTTP_IF_MODIFIED_SINCE'])//eg:Sun, 02 Nov 2008 07:08:25 GMT; length=35849 { $array=explode(' ',$_SERVER['HTTP_IF_MODIFIED_SINCE']); $gmday=$array[1]; $month_array=array( "Jan"=>"01", "Feb"=>"02", "Mar"=>"03", "Apr"=>"04", "May"=>"05", "Jun"=>"06", "Jul"=>"07", "Aug"=>"08", "Sep"=>"09", "Oct"=>"10", "Nov"=>"11", "Dec"=>"12"); $gmmonth=$month_array[$array[2]]; $gmyear=$array[3]; $array=explode(':',$array[4]); $gmtimestamp=gmmktime($array[0],$array[1],$array[2],$gmmonth,$gmday,$gmyear); if(gmmktime()-$gmtimestamp<$config_client_cache_time*60*60) { header('Etag:phpblog',true,304);//控制瀏覽器緩存 $_SESSION['time_end']=microtime(true); exit(); } }
緩存的HEADER是這樣來(lái)發(fā)送的:
PHP 代碼復(fù)制到剪貼板
復(fù)制代碼 代碼如下:
$client_cache_time=$config_client_cache_time*60*60;//單位 - 秒
header('Cache-Control: public, max-age='.$client_cache_time);
header('Expires: '.gmdate('D, d M Y H:i:s',time()+$client_cache_time).' GMT');//設(shè)置頁(yè)面緩存時(shí)間
header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');//返回最后修改時(shí)間
header('Pragma: public');
header('Etag:phpblog');//返回標(biāo)識(shí),用于標(biāo)識(shí)上次的確訪問(wèn)過(guò)(瀏覽器中存在緩存)
$client_cache_time=$config_client_cache_time*60*60;//單位 - 秒 header('Cache-Control: public, max-age='.$client_cache_time); header('Expires: '.gmdate('D, d M Y H:i:s',time()+$client_cache_time).' GMT');//設(shè)置頁(yè)面緩存時(shí)間 header('Last-Modified: '.gmdate('D, d M Y H:i:s',time()).' GMT');//返回最后修改時(shí)間 header('Pragma: public'); header('Etag:phpblog');//返回標(biāo)識(shí),用于標(biāo)識(shí)上次的確訪問(wèn)過(guò)(瀏覽器中存在緩存)
您可能感興趣的文章:
- PHP下利用header()函數(shù)設(shè)置瀏覽器緩存的代碼
- php禁止直接從瀏覽器輸入地址訪問(wèn).php文件的方法
- 兼容ie6瀏覽器的php下載文件代碼分享
- php強(qiáng)制文件下載而非在瀏覽器打開(kāi)的自定義函數(shù)分享
- php導(dǎo)出csv數(shù)據(jù)在瀏覽器中輸出提供下載或保存到文件的示例
- PHP限制頁(yè)面只能在微信自帶瀏覽器訪問(wèn)的代碼
- PHP實(shí)現(xiàn)根據(jù)瀏覽器跳轉(zhuǎn)不同語(yǔ)言頁(yè)面代碼
- 使用php判斷瀏覽器的類(lèi)型和語(yǔ)言的函數(shù)代碼
- 控制PHP的輸出:緩存并壓縮動(dòng)態(tài)頁(yè)面
- php頁(yè)面緩存ob系列函數(shù)介紹
- PHP禁止頁(yè)面緩存的代碼
- php 禁止頁(yè)面緩存輸出
- php禁止瀏覽器使用緩存頁(yè)面的方法
相關(guān)文章
PHP通過(guò)curl獲取接口URL的數(shù)據(jù)方法
今天小編就為大家分享一篇PHP通過(guò)curl獲取接口URL的數(shù)據(jù)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-05-05ThinkPHP5查詢(xún)數(shù)據(jù)及處理結(jié)果的方法小結(jié)
這篇文章主要介紹了ThinkPHP5查詢(xún)數(shù)據(jù)及處理結(jié)果的方法,結(jié)合實(shí)例總結(jié)分析了thinkPHP5常見(jiàn)查詢(xún)語(yǔ)句及查詢(xún)數(shù)據(jù)庫(kù)的三種方式,需要的朋友可以參考下2017-11-11php版微信公眾平臺(tái)入門(mén)教程之開(kāi)發(fā)者認(rèn)證的方法
這篇文章主要介紹了php版微信公眾平臺(tái)入門(mén)教程之開(kāi)發(fā)者認(rèn)證的方法,結(jié)合實(shí)例形式分析了php版微信公眾平臺(tái)開(kāi)發(fā)者認(rèn)證的步驟與相關(guān)操作技巧,需要的朋友可以參考下2016-09-09PHP生成短網(wǎng)址的思路以及實(shí)現(xiàn)方法的詳解
今天小編就為大家分享一篇關(guān)于PHP生成短網(wǎng)址的思路以及實(shí)現(xiàn)方法的詳解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03