2010-06-04 122 views
4

我有一個PHP文件,每次都會使用相同的$ _GET參數返回相同的內容 - 這是確定性的。如果PHP頁面沒有被修改,使得PHP頁面返回「304 Not Modified」

不幸的是,爲了提高效率(這個文件經常被請求),每當PHP頁面被請求時,Apache默認爲「200 OK」響應,使得用戶再次下載文件。

有沒有什麼辦法可以發送304 Not Modified頭文件當且僅當的參數相同?

獎金: 我可以設置它的到期時間,因此,如果緩存的頁面比說,老三多天,它發送一個「200 OK」的迴應?

回答

10

沒有緩存的頁面自己(或至少它的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

+0

這似乎是我的一般想法。 – 2010-06-05 00:45:04

+0

儘管對於OP,沒有必要緩存任何內容。根據他的條件,他可以根據id來計算Etag。 – 2010-06-05 01:46:51

+0

是的,實際的實施可以根據需要簡單或精心製作。試圖說明這一點,但我陷入了提供實施的缺陷,md5()對內容不應該存在:P – Wrikken 2010-06-05 03:26:30

2

你試過header("HTTP/1.0 304 Not Modified");在你的PHP代碼中被調用嗎?如果不熟悉,您會在開始向緩衝區輸出任何內容之前將其放入代碼中。

http://php.net/manual/en/function.header.php

+0

我應該叫每次當腳本訪問? – 2010-06-05 00:09:34

7

一般情況下,返回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參數緩存副本的映射,順便說一句。你不需要在那裏做任何工作。

0

這個腳本會再次渲染整個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");