首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 动态图片输出 CDN 缓存失效解决方案:ETag + Last-Modified + 304 实战

     編輯:PHP 綜合知識

PHP 动态生成图片(如缩略图、水印图)直接输出时,缺乏 HTTP 缓存协商头,导致 CDN 每次回源,后端压力剧增。本文给出标准 ETag/Last-Modified + 304 Not Modified 完整实现,让动态图片同样享受 CDN/浏览器强缓存与协商缓存。

核心代码

image 为图片二进制内容或文件路径
$etag = md5($this->image); // 基于内容生成 ETag

// 1. 协商缓存:检查 If-None-Match (ETag)
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
    $client_etag = $_SERVER['HTTP_IF_NONE_MATCH'];
    if ($client_etag === $etag) {
        header("HTTP/1.1 304 Not Modified");
        exit;
    }
}

// 2. 协商缓存:检查 If-Modified-Since (Last-Modified)
// $last_modified = gmdate("D, d M Y H:i:s", filemtime($image_path)) . " GMT";
// if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { ... }

// 3. 发送缓存控制头
header("Last-Modified: " . gmdate("D, d M Y H:i:s", strtotime('2011-1-1')) . " GMT");
header('ETag: ' . $etag);
header('Cache-Control: max-age=2592000, public'); // 30 天强缓存

// 4. 输出图片
echo $this->image;
?>

HTTP 缓存流程图解

  1. 首次请求:服务端返回 200 OK + ETag + Last-Modified + Cache-Control。CDN/浏览器缓存响应体与头。
  2. 再次请求:客户端自动发送 If-None-Match: <etag> 和/或 If-Modified-Since: <date>。
  3. 服务端比对:一致 → 304 Not Modified(空响应体),客户端直接读缓存;不一致 → 200 OK 返回新内容。

关键坑点与修正

  • FastCGI 未传递 HTTP_IF_NONE_MATCH:Nginx 默认已将所有 HTTP 头映射为 $_SERVER['HTTP_*'](大写、下划线、减号转下划线)。无需在 fastcgi_param 重复配置。若缺失,检查 fastcgi_pass_header 或 proxy_pass_header 设置。
  • ETag 计算成本:大文件用 md5_file() 或 sha1_file() 避免全量读入内存;或用 filemtime()+filesize() 组合作为弱 ETag。
  • 分布式部署:多台服务器需保证同一文件 ETag 一致(用内容哈希而非 inode)。
  • Cache-Control 策略:public 允许 CDN 缓存,max-age 控制强缓存时间,must-revalidate 过期后必须回源验证。

Nginx 配置参考

location ~* \.(jpg|jpeg|png|gif|webp)$ {
    # PHP 动态图片路由已处理缓存头,此处仅作兜底
    expires 30d;
    add_header Cache-Control "public";
    # 关闭 Nginx 自身 ETag 避免冲突(可选)
    # etag off;
}

补全 HTTP 缓存协商头,动态图片瞬间具备静态资源级 CDN 加速能力,后端压力降 90%+。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved