304:未修改和前端缓存

时间:2009-10-18 01:38:03

标签: php http caching http-headers

我正在使用PHP脚本来提供文件。 如果自客户端上次下载文件后文件没有更改,我希望能够在我的http响应中发回304未修改的标头。这似乎是Apache(以及大多数其他Web服务器)的一个功能,但我不知道如何通过PHP实现这一功能。

我听说过使用$_SERVER['HTTP_IF_MODIFIED_SINCE'],但这个变量似乎没有出现在我的$_SERVER超级数组中。

我的问题不是如何返回304标题,而是如何知道应该返回标题。


编辑:问题是我的$_SERVER['HTTP_IF_MODIFIED_SINCE']未设置。这是我的.htaccess文件的内容:

ExpiresActive On 
ExpiresByType image/jpeg "modification plus 1 month"
ExpiresByType image/png "modification plus 1 month"
ExpiresByType image/gif "modification plus 1 month"
Header append Cache-Control: "must-revalidate" 


<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond $1 !^(controller\.php)
   RewriteRule (.*\.jpg|.*\.png|.*\.gif) controller.php/$1
</IfModule>

HTTP_IF_MODIFIED_SINCE仍未出现在$_SERVER超级数组中。

6 个答案:

答案 0 :(得分:26)

HTTP_IF_MODIFIED_SINCE是正确的方法。如果您没有得到它,请检查Apache是​​否启用了mod_expiresmod_headers并且正常工作。借用a comment on PHP.net

$last_modified_time = filemtime($file); 
$etag = md5_file($file);
// always send headers
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT"); 
header("Etag: $etag"); 
// exit if not modified
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time || 
    @trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { 
    header("HTTP/1.1 304 Not Modified"); 
    exit; 
}

// output data

答案 1 :(得分:1)

This article将回答有关缓存的所有问题

我发现添加了

RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}]
RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}]

在我的htaccess文件的底部(在所有rewriterule下面)工作。

答案 2 :(得分:0)

<{1}}关闭后,

$_SERVER['HTTP_IF_MODIFIED_SINCE']通常为空。

检查是否是这种情况,如果是,请尝试register_globals

答案 3 :(得分:0)

还有一些其他参数要检查..在我的情况下,我没有这两个标题:

$_SERVER['HTTP_IF_NONE_MATCH'] && $_SERVER['HTTP_IF_MODIFIED_SINCE']

需要返回一个正确的304标题,因为我的系统时钟有点晚了,它会将这些页面解释为将来到期,然后根本不发送这些值

同时检查apache返回的标头,或者至少将其覆盖为更大的值

Cache-Control: max-age=3600

如果

,它不会发送以前的标题
Last-Modified previous sent header < ( NOW - 3600 )

所以在我的情况下,我设置了这个非常方便的功能 function lastModified($file){ $x=filemtime($file); while($x>time())$x-=86000;}#reduce by one day if touched in future date $date=gmdate('D, j M Y H:i:s',$x).' GMT'; header('Cache-Control: max-age=86000',1); if($_SERVER['HTTP_IF_NONE_MATCH'] == $x || $_SERVER['HTTP_IF_MODIFIED_SINCE']==$date){ header('HTTP/1.1 304 Not Modified',1,304);die;} header('Etag: '.$x,1);header('Last-Modified: '.$date,1); }

答案 4 :(得分:0)

我遇到了这个问题,结果只是我打开了Firebug。这在默认情况下勾选的网络选项卡“禁用浏览器缓存”下有一个选项。 Chrome的开发者工具中有一个类似的选项,菜单栏下栏上的一个勾选框。

取消这些选项会导致浏览器正确发送HTTP_IF_MODIFIED_SINCE,一切正常(即使打开Firebug或Chrome开发工具)。

答案 5 :(得分:0)

请注意, $ _ SERVER [“ HTTP_IF_NONE_MATCH”] 可以包含引号和-gzip后缀。

$server_etag = str_replace("-gzip", "", str_replace('"', '', stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])));

if ($server_etag == $etag) ...