能缓存php生成的html,但需绕过php执行:将php渲染结果写为静态文件,由nginx直接响应并返回cache-control: public头,cdn据此缓存;回源路径须分离,避免nginx将静态请求转发给php。

CDN 能缓存 PHP 生成的 HTML 吗?
不能直接缓存。CDN 缓存的是响应体(body)和响应头(headers),但默认会忽略带 Set-Cookie、Cache-Control: no-cache 或 Vary: Cookie 的响应。PHP 脚本若输出了这些头,CDN 就会跳过缓存——哪怕内容本身是静态的。
常见错误现象:curl -I https://example.com/index.php 返回 Cache-Control: no-store, no-cache, must-revalidate,此时无论 CDN 配置多完善,资源都不会进边缘节点。
- 检查 PHP 输出前是否调用了
session_start()(自动加Cache-Control: no-cache和Set-Cookie) - 确认没手动调用
header('Cache-Control: ...')覆盖为不可缓存策略 - 避免在 HTML 中混写动态逻辑(如
<?php echo date('Y'); ?>),否则缓存失效且无法预判
如何让 PHP 页面被 CDN 缓存(不改框架的前提下)
核心思路:把「页面生成」和「页面分发」解耦。PHP 只负责生成一次 HTML,存到可被 CDN 直接拉取的路径,之后完全绕过 PHP 解释器。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
file_put_contents()把渲染结果写入/public/cache/about.html这类静态路径,再用 CDN 回源该目录 - 配合 Nginx 配置优先匹配静态文件:
try_files $uri $uri/ /index.php?$query_string;→ 改为try_files $uri @php;,把 PHP 作为兜底而非默认 - 给静态 HTML 加上明确缓存头:
header('Cache-Control: public, max-age=3600');(注意:此 header 必须由 Web 服务器(如 Nginx)发出,不是 PHP 输出)
关键点:CDN 看到的是 Nginx 返回的 200 OK + Cache-Control: public,才真正触发缓存;PHP 只在首次生成或更新时运行。
CDN 回源时怎么避开 PHP 处理静态资源?
典型陷阱:CDN 回源地址设成 https://origin.example.com/,而 Nginx 把所有请求都转给 index.php(如 Laravel 的 try_files $uri $uri/ /index.php?$query_string;)。结果 CDN 每次回源都在执行 PHP,缓存形同虚设。
正确做法是分离回源路径:
- 静态资源(CSS/JS/IMG)走专用子域名或路径,例如
https://static.example.com/或https://origin.example.com/static/ - Nginx 对
/static/路径禁用 PHP 处理:location ^~ /static/ { add_header Cache-Control "public, max-age=31536000"; } - 确保 PHP 不参与这些路径的响应——删掉
location ~ \.php$对该前缀的匹配
验证方式:curl -I https://origin.example.com/static/main.css 应返回 200 且无 X-Powered-By 或 X-PHP-Version 头。
PHP 如何安全触发 CDN 缓存刷新?
CDN 缓存刷新不是靠 PHP 主动“推”,而是靠你调用 CDN 提供的 API 接口(如阿里云 RefreshObjectCaches、Cloudflare /zones/{zone_id}/purge_cache)。PHP 只是发起 HTTP 请求的客户端。
注意事项:
- 不要在每次页面更新后都全站刷新——用
url列表精准刷新,例如只提交https://example.com/about.html和https://example.com/css/app.css - 注意 API 频率限制(如阿里云默认 100 次/天),失败时记录
error_log()而非静默吞掉 - 敏感操作加判断:
if (is_production() && !is_cli()) { /* 调用刷新接口 */ },防止本地开发误刷线上
最容易被忽略的一点:CDN 刷新的是「URL」,不是「文件路径」。你改了 /public/css/app.css?v=2,就得刷新这个带参数的完整 URL,而不是只刷 /css/app.css —— 否则旧版本仍可能被缓存命中。











