You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PHP如何实现过期缓存与内容更新触发的智能刷新缓存,及缓存头设置失效问题解决

如何在PHP中实现带过期机制且支持内容更新自动刷新的缓存

一、先解决你当前HTTP缓存失效的问题

你现在的代码只设置了过期头,但没处理浏览器的If-Modified-Since请求头,导致每次浏览器都会重新请求完整内容,而不是复用本地缓存。要让HTTP缓存正常工作,服务器端得验证资源是否已修改,返回304状态码让浏览器直接用缓存。

修正后的代码示例:

<?php
$seconds_to_cache = 300;
// 用内容的最后修改时间(如果是动态内容,换成数据库内容的更新时间)
$last_modified_time = filemtime(__FILE__);
// 用内容哈希作为ETag,更精准标识资源版本
$etag = md5_file(__FILE__);

// 发送资源版本标识头
header("Last-Modified: " . gmdate("D, d M Y H:i:s", $last_modified_time) . " GMT");
header("ETag: $etag");

// 检查浏览器携带的缓存验证信息
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $last_modified_time || 
    trim($_SERVER['HTTP_IF_NONE_MATCH']) === $etag) {
    // 资源未修改,返回304让浏览器用缓存
    header("HTTP/1.1 304 Not Modified");
    exit;
}

// 设置缓存过期规则
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $seconds_to_cache) . " GMT");
header("Cache-Control: max-age=$seconds_to_cache, public");
header("Pragma: cache");

// 这里是你的页面内容输出逻辑
echo "当前时间:" . date('Y-m-d H:i:s');
?>

简单解释下:

  • Last-ModifiedETag是给浏览器的资源版本标记,后续请求浏览器会带上这些信息
  • 服务器对比这些标记,确认资源没变化就返回304,浏览器直接用本地缓存,不用重新下载内容
  • 如果是动态生成的内容(比如从数据库取数据),把filemtime(__FILE__)换成内容的最后更新时间,md5_file(__FILE__)换成内容的哈希值就行

二、实现内容更新时自动刷新的智能缓存

HTTP缓存适合静态或低频变化的内容,但要做到内容一更新就自动刷新缓存,更靠谱的是用服务器端缓存(文件缓存、Redis都可以),核心思路是给缓存绑定一个「版本标识」,内容更新时版本标识变化,缓存自动失效。

方案1:文件缓存(适合小型站点)

<?php
// 缓存文件存储路径
$cache_file = './cache/home_page.cache';
// 内容版本标识:比如从数据库取最新内容的更新时间
$content_version = get_content_last_update_time();

// 检查缓存是否有效
if (file_exists($cache_file)) {
    $cache_data = unserialize(file_get_contents($cache_file));
    // 版本一致+未过期,直接输出缓存
    if ($cache_data['version'] === $content_version && time() < $cache_data['expire_time']) {
        echo $cache_data['content'];
        exit;
    }
}

// 缓存无效,生成最新页面内容
$page_content = generate_page_content();

// 保存新缓存,同时记录版本和过期时间
$cache_data = [
    'version' => $content_version,
    'content' => $page_content,
    'expire_time' => time() + 300 // 双重保险:即使版本标识没更新,缓存也会过期
];
file_put_contents($cache_file, serialize($cache_data));

// 输出内容
echo $page_content;

// 辅助函数示例:获取内容最后更新时间
function get_content_last_update_time() {
    $pdo = new PDO('mysql:host=localhost;dbname=your_db', 'user', 'password');
    // 假设你有articles表,取最新修改的文章时间
    $stmt = $pdo->query("SELECT MAX(updated_at) FROM articles");
    return $stmt->fetchColumn();
}

// 辅助函数示例:生成页面内容
function generate_page_content() {
    // 这里写你的页面渲染逻辑,比如从数据库取数据生成HTML
    return "<h1>最新文章列表</h1>" . date('Y-m-d H:i:s');
}
?>

这个方案的好处是:只要内容更新(比如数据库里的文章被修改),$content_version就会变化,缓存直接失效,下次请求自动生成新缓存,同时还保留了过期时间,避免版本标识更新失败导致缓存永久有效。

方案2:Redis缓存(适合高并发站点)

如果你的网站流量较大,用Redis这类内存缓存效率更高,思路和文件缓存一致,只是把缓存存在Redis里:

<?php
$redis = new Redis();
$redis->connect('localhost', 6379);

$cache_key = 'cache:home_page';
$content_version = get_content_last_update_time();
$cache_data = $redis->get($cache_key);

if ($cache_data) {
    $cache_data = json_decode($cache_data, true);
    if ($cache_data['version'] === $content_version) {
        echo $cache_data['content'];
        exit;
    }
}

// 生成最新内容
$page_content = generate_page_content();

// 保存到Redis,同时设置过期时间
$redis->set($cache_key, json_encode([
    'version' => $content_version,
    'content' => $page_content
]));
$redis->expire($cache_key, 300);

echo $page_content;
?>

三、额外注意事项

  • 如果页面有用户个性化内容(比如登录用户的专属信息),要给缓存key加上用户ID,避免不同用户看到相同的缓存内容
  • 开发环境可以临时关闭缓存:header("Cache-Control: no-cache, no-store, must-revalidate");,方便调试
  • 对于数据库驱动的内容,记得在修改、添加数据后,确保get_content_last_update_time能返回最新的时间戳

内容的提问来源于stack exchange,提问作者Sash

火山引擎 最新活动