本文目录导读:

在PHP项目中设置CDN回源缓存规则,通常需要从CDN控制台配置和源站(PHP服务器)响应头两个层面协同完成,以下是系统化的操作指南和最佳实践。
核心原则:通过HTTP响应头控制CDN缓存
CDN节点是否缓存文件,以及缓存多久,主要取决于源站返回的HTTP响应头(Cache-Control、Expires、Last-Modified等),PHP程序需要主动输出这些头信息。
在PHP中设置缓存头
静态资源(CSS、JS、图片等):
// 设置强缓存:浏览器和CDN均缓存1年
header('Cache-Control: public, max-age=31536000, immutable');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 31536000) . ' GMT');
public:允许CDN和中间代理缓存。max-age:缓存生效秒数(31536000秒=1年)。immutable:指示浏览器无需重新验证(仅Chrome/Firefox支持)。
动态HTML页面(可缓存但需更新):
// 缓存10分钟,超过时间需回源验证
header('Cache-Control: public, max-age=600, must-revalidate');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime(__FILE__)) . ' GMT');
must-revalidate:缓存过期后必须回源检查文件是否修改。
登录态、个人数据(禁止缓存):
// 绝对不缓存(适合API、用户中心等)
header('Cache-Control: private, no-store, no-cache, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
使用.htaccess/Nginx配置文件(静态文件更高效)
如果不想修改PHP代码,可在Web服务器层面设置缓存规则:
Apache (.htaccess):
<FilesMatch "\.(css|js|jpg|png|gif|ico|svg|woff2?)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
<FilesMatch "\.(html|php)$">
Header set Cache-Control "public, max-age=600, must-revalidate"
</FilesMatch>
Nginx (server block):
location ~* \.(css|js|jpg|png|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location ~* \.(html|php)$ {
expires 10m;
add_header Cache-Control "public, must-revalidate";
}
在CDN控制台设置缓存规则(以腾讯云/阿里云为例)
即使源站返回了缓存头,CDN节点也可能需要额外配置来覆盖或强化规则。
设置优先级:CDN缓存规则 > 源站响应头(通常可配置)
大多数CDN支持强制缓存或缓存规则优先级:
- 遵循源站:完全按照PHP返回的
Cache-Control执行。 - CDN强制缓存:忽略源站头,强制缓存指定秒数(适合静态资源)。
- CDN覆盖源站:以CDN规则为准。
典型CDN缓存规则配置
| 文件类型 | CDN缓存时间 | 回源策略 | 说明 |
|---|---|---|---|
*.css, *.js, *.jpg |
30天 | 源站返回304则缓存 | 增量更新时建议加版本号(如style.css?v=2) |
*.html |
10分钟 | 始终回源验证 | 内容更新频率高的页面 |
*.php |
0秒(不缓存) | 透传 | 动态PHP脚本通常不缓存 |
/api/* |
不缓存 | 透传 | API接口必须实时更新 |
高级:忽略URL参数(提升命中率)
如果PHP页面通过?id=123参数动态生成内容,但CDN缓存了不同参数版本,会导致缓存碎片化,建议:
- 在CDN控制台开启忽略URL参数(按需选择“全部忽略”或“保留指定参数”)。
- 如果参数影响内容(如分页
?page=2),可考虑将参数移入PATH(如/list/2.html),或使用Cookie/Token等方式传递。
PHP动态内容的特殊处理
缓存允许但需及时更新的场景(如新闻列表)
// 输出时记录最后修改时间
$lastModified = 'Wed, 21 Oct 2023 07:28:00 GMT';
header('Last-Modified: ' . $lastModified);
// 检查客户端缓存是否有效
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= strtotime($lastModified)) {
header('HTTP/1.1 304 Not Modified');
exit;
}
// 否则正常输出内容
使用ETag(更精确的内容指纹)
$content = getContent();
$etag = md5($content);
header('ETag: "' . $etag . '"');
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) &&
trim($_SERVER['HTTP_IF_NONE_MATCH'], '"') == $etag) {
header('HTTP/1.1 304 Not Modified');
exit;
}
echo $content;
验证配置是否生效
检查响应头
使用浏览器开发者工具或curl -I https://yourdomain.com/path:
curl -I https://cdn.example.com/static/js/app.js # 期望看到: # Cache-Control: public, max-age=31536000 # age: 12345 # CDN节点缓存已存在的时间 # x-cache: HIT # 表示从CDN缓存命中
回源测试
# 强制从CDN回源(添加特定参数,如 ?timestamp=xxx) curl -H "Cache-Control: no-cache" https://cdn.example.com/index.html
常见问题与排查
CDN缓存了错误内容(如用户登录态泄漏)
- 原因:未对动态内容设置
private或no-cache。 - 解决:PHP代码中对用户相关URL输出
Cache-Control: private, no-store。
修改了文件但CDN缓存未刷新
- 使用版本号:在文件名后加
?v=2或直接改名(如style.css→style.abc123.css)。 - CDN刷新:手动刷新CDN节点缓存(控制台操作或API调用)。
PHP动态URL(如/article.php?id=1)命中率低
- 方案不随用户变化,在CDN控制台开启忽略URL参数(前提是所有参数对内容无影响)。
- 更好方案:使用URL重写,将
/article/1映射到/article.php?id=1,CDN缓存完整的路径。
推荐配置模板
PHP源站(.htaccess或Nginx config):
# 静态资源 - 长期缓存
.css, .js, .jpg, .png, .gif, .ico, .svg, .woff2 → Cache-Control: public, max-age=31536000
# 页面文档 - 短时间缓存
.html, .htm → Cache-Control: public, max-age=600
# PHP动态内容 - 遵循PHP代码中的设置
.php, .php3, .php4 → 不设置通用规则,由代码控制
# 禁止缓存 - API或后台路径
/admin/*, /api/*, /login/* → Cache-Control: private, no-store
CDN控制台:
| 路径 | 缓存时间 | 策略 |
|-----|---------|------|
| *.js?* | 30天 | 强制缓存 |
| *.css?* | 30天 | 强制缓存 |
| /static/* | 30天 | 强制缓存 |
| 其他路径 | 遵循源站 | 回源时传递Accept-Encoding |
- 静态资源:强制长时间缓存(1年),配合版本号更新。
- 动态页面:根据更新频率设置短时间缓存(如10分钟),配合
Last-Modified/ETag验证。 - :明确禁止缓存(
private, no-store)。 - 验证:通过响应头中的
age和x-cache确认CDN缓存命中情况。
遵循“源站输出正确响应头 + CDN控制台规则补充”的策略,即可高效管理PHP项目的CDN回源缓存。