我有一個PHP文件,每次都會使用相同的$ _GET參數返回相同的內容 - 這是確定性的。如果PHP頁面沒有被修改,使得PHP頁面返回「304 Not Modified」
不幸的是,爲了提高效率(這個文件經常被請求),每當PHP頁面被請求時,Apache默認爲「200 OK」響應,使得用戶再次下載文件。
有沒有什麼辦法可以發送304 Not Modified
頭文件當且僅當的參數相同?
獎金: 我可以設置它的到期時間,因此,如果緩存的頁面比說,老三多天,它發送一個「200 OK」的迴應?
我有一個PHP文件,每次都會使用相同的$ _GET參數返回相同的內容 - 這是確定性的。如果PHP頁面沒有被修改,使得PHP頁面返回「304 Not Modified」
不幸的是,爲了提高效率(這個文件經常被請求),每當PHP頁面被請求時,Apache默認爲「200 OK」響應,使得用戶再次下載文件。
有沒有什麼辦法可以發送304 Not Modified
頭文件當且僅當的參數相同?
獎金: 我可以設置它的到期時間,因此,如果緩存的頁面比說,老三多天,它發送一個「200 OK」的迴應?
沒有緩存的頁面自己(或至少它的Etag),你不能很好的運用了304的全功能的緩存算法有點超出範圍的,但一般的概念:
<?php
function getUrlEtag($url){
//some logic to get an etag, possibly stored in memcached/database/file etc.
}
function setUrlEtag($url,$etag){
//some logic to get an etag, possibly stored in memcached/database/file etc.
}
function getPageCache($url,$etag=''){
//[optional]some logic to get the page from cache instead, possibly not even using etag
}
function setPageCache($url,$content,$etag=''){
//[optional]some logic to save the page to cache, possibly not even using etag
}
ob_start();
$etag = getUrlEtag($_SERVER['REQUEST_URI']);
if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
header("HTTP/1.1 304 Not Modified");
exit;
}
if(($content=getPageCache($_SERVER['REQUEST_URI'],$etag))!==false){
echo $content;
exit;
}
?>
//the actual page
<?php
$content = ob_get_clean();
setUrlEtag($_SERVER['REQUEST_URI'],$etag=md5($url.$content));
function setPageCache($_SERVER['REQUEST_URI'],$content,$etag);
header("Etag: $etag");
echo $content;
?>
所有常見應用陷阱:您可能無法顯示登錄用戶的緩存頁面,緩存部分內容可能更可取,您自己負責防止緩存中的陳舊內容(可能在後端或修改數據庫時使用觸發器,或者只是播放圍繞着getUrlEtag
邏輯)等等。
You co如果這更容易控制,那麼也可以玩HTTP_IF_MODIFIED_SINCE
。
你試過header("HTTP/1.0 304 Not Modified");
在你的PHP代碼中被調用嗎?如果不熟悉,您會在開始向緩衝區輸出任何內容之前將其放入代碼中。
我應該叫每次當腳本訪問? – 2010-06-05 00:09:34
一般情況下,返回HTTP使用的頭功能狀態代碼:
Header("HTTP/1.1 304 Not Modified");
exit();
然而,僅此是不夠的。
問題是你不知道如何請求文件,所以你需要一點瀏覽器的合作。
您可以在傳入請求中查找If-modified-since
標題,並返回相應的狀態碼(如果存在且處於日期範圍內)。
如果您在最初生成PHP時發送正確的Expires
標題,則瀏覽器或代理緩存可能決定根本不提取請求(儘管更有可能它們將設置標頭If-modified-since
)。如果沒有Expires
標題,瀏覽器可能會重新嘗試完整的請求。
欲瞭解更多信息,請參閱http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html並搜索「14.25」
瀏覽器將做GET
參數緩存副本的映射,順便說一句。你不需要在那裏做任何工作。
這個腳本會再次渲染整個PHP腳本,但是之後它會檢查ETag是否等於輸出字符串的MD5,如果是,它會發送一個304並且不使用帶寬。 您還可以創建這樣的事情與所有的查詢字符串等MD5和存儲在某個地方,你不會需要重新輸出內容(甚至更快)
function sanitize_output($buffer) {
$headers = apache_request_headers();
$tt5=md5($buffer);
header('ETag: '.$tt5);
if (isset($headers['If-None-Match']) && $headers['If-None-Match']===$tt5) {
header('HTTP/1.1 304 Not Modified');
header('Connection: close');
exit();
}
return $buffer;
}
ob_start("sanitize_output");
這似乎是我的一般想法。 – 2010-06-05 00:45:04
儘管對於OP,沒有必要緩存任何內容。根據他的條件,他可以根據id來計算Etag。 – 2010-06-05 01:46:51
是的,實際的實施可以根據需要簡單或精心製作。試圖說明這一點,但我陷入了提供實施的缺陷,md5()對內容不應該存在:P – Wrikken 2010-06-05 03:26:30