PHP 静态文件返回 304 Not Modified 缓存技巧
当 PHP 动态输出图片等静态资源时,默认往往每次都向服务器发起完整请求并返回 200 状态,造成不必要的带宽消耗。通过引入 HTTP 缓存机制,利用 Last-Modified 和 Etag 头信息,可以在客户端发现资源未发生变化时返回 304 Not Modified,从而让浏览器直接使用本地缓存副本。
为什么需要返回 304?
在 Web 开发中,即使图片本身没有改变,如果服务器不告知客户端 "未修改",浏览器仍会重新下载整个文件。这对于高频访问的图片资源是极大的性能浪费。通过验证资源指纹(时间戳或哈希值),我们可以精确控制缓存行为。
实现原理与准备工作
HTTP/1.1 提供了两种标准的缓存验证机制:
- If-Modified-Since / Last-Modified:基于时间的比较。服务器发送资源的最后修改时间,客户端下次请求携带该时间,若相同则返回 304。
- If-None-Match / Etag:基于内容的唯一标识符(通常由 MD5 或 CRC32 生成)。只要文件内容微调,标识符就会改变。
为了最高效地使用这两个机制,我们需要获取两个关键数据:
1. 文件的最后修改时间戳(filemtime)。
2. 文件的唯一标识字符串(如 md5_file 生成的哈希值)。
具体操作步骤
第1步:构建 304 缓存验证函数
目的:封装逻辑,复用性强。
入口:被调用的 PHP 脚本或基类。
动作:解析请求头中的验证信息,并与当前文件属性比对。若匹配,发送 304 头并终止脚本。
private function _addEtag($file) {
// 1. 获取文件的最后修改时间和内容哈希值
$last_modified_time = filemtime($file);
$etag = md5_file($file);
// 2. 始终发送响应头,供首次请求的客户端缓存
header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
header("Etag: \"$etag\"");
// 3. 检查客户端是否携带了旧的验证信息
// 注意:$_SERVER['HTTP_IF_MODIFIED_SINCE'] 可能包含毫秒,需转换处理
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time ||
@trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) {
// 4. 内容未变,发送 304 状态码并退出,不传输任何 Body
header("HTTP/1.1 304 Not Modified");
exit;
}
}
参数说明:
- $file: 待服务的静态文件路径。
- header("Etag: ..."): 注意标准规范中 Etag 值通常需要加双引号,上面代码中已加入以确保兼容最佳实践。
第2步:在输出资源前调用验证函数
目的:拦截不符合条件的请求。
入口:在你的图片处理或文件服务脚本的最开头。
动作:传入文件路径,函数内部完成计算。如果命中缓存,直接退出;否则,继续执行下方的图片输出逻辑。
示例调用场景:
假设你有一个 image.php 用于显示用户上传的头像。
<?php
$imagePath = 'uploads/avatar/user_123.jpg';
if (file_exists($imagePath)) {
// 先调用 304 检测
$_addEtag = function($f) {
// ... 此处粘贴上述 _addEtag 的代码逻辑
};
$_addEtag($imagePath);
// 只有通过了上面的 exit(),才会执行到这里
header('Content-Type: image/jpeg');
echo file_get_contents($imagePath);
}
?>
完成判断
- 首次访问:浏览器接收带有
Last-Modified和Etag的完整图片数据及 200 状态。 - 再次访问(无更改):浏览器自动携带
If-Modified-Since和If-None-Match请求头。服务器判定一致后,返回空正文且仅含 304 状态的响应。 - 查看效果:打开浏览器开发者工具(F12)→ Network(网络)面板,刷新页面。观察该图片请求的状态码是否为
304,且 Size 列为(disk cache)或(memory cache)。
简要总结
通过在 PHP 层集成基于 filemtime 和 md5_file 的验证逻辑,可以有效复用浏览器的 HTTP 缓存能力。这不仅减少了服务器负载,也降低了用户的等待时间。以上就是利用 PHP Etag 和 Last-Modified 实现 304 缓存优化的详细内容,更多关于 PHP 性能优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













