通过为Nginx服务器配置HTTP缓存策略,可指示浏览器和中间代理(如CDN)缓存静态资源(如图片、CSS、JS 文件),并在缓存有效期内直接从本地加载,无需向服务器发起请求。此举可提升网站加载速度,并降低服务器的带宽消耗与处理压力。
常用缓存策略示例
本节提供常见的缓存配置方案,可根据场景直接应用于Nginx配置文件。所有示例均使用 add_header ... always;,确保在所有响应码(包括304 Not Modified)下都能添加缓存头。
场景一:为静态资源设置长期缓存
# 为静态资源设置长期缓存
# - 若文件名包含内容哈希(如 main.a1b2c3d4.js),推荐使用 1 年 + immutable
location ~* "\.[a-f0-9]{8,}\.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$" {
# 适用于构建工具生成的带哈希资源:缓存1年,浏览器永不验证
add_header Cache-Control "public, max-age=31536003, immutable" always;
access_log off;
}
# - 若文件名固定且极少变更(如 logo.png),使用 30 天缓存
location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ {
# 适用于无哈希的通用静态资源:缓存30天,允许CDN和浏览器缓存
add_header Cache-Control "public, max-age=2592000" always;
access_log off;
}场景二:为HTML文档或单页应用(SPA)入口配置缓存策略
对于HTML页面(尤其是单页应用的入口文件,如 index.html),由于其内容可能随应用部署频繁更新,不应设置长期缓存。但为兼顾性能,可允许浏览器缓存,并在每次使用前向服务器验证资源是否变更。
# 适用于直接请求的 HTML 文件
location ~* \.html$ {
# 允许浏览器缓存,但每次使用前必须向服务器验证
# 'private' 禁止中间代理(如CDN)缓存此响应
# 服务器需提供 ETag 或 Last-Modified 以支持验证
add_header Cache-Control "private, no-cache, must-revalidate" always;
}此策略依赖服务器返回
ETag或Last-Modified响应头,以便浏览器发起条件请求。Nginx默认为静态文件提供这些头,无需额外配置。为防止中间代理(如 CDN)缓存HTML内容,建议使用"private"指令,确保仅浏览器可缓存。
场景三:禁止缓存动态内容或敏感信息
对于 API 接口、用户个人中心、支付页面等动态生成或包含敏感数据的内容,必须禁止浏览器及所有中间代理(如CDN、共享缓存)存储任何响应副本,以防止信息泄露或数据不一致。
# 示例:适用于 PHP 动态脚本(请根据实际动态路径调整)
location ~ \.php$ {
# ... 其他 PHP-FPM 配置 ...
# 禁止所有缓存:浏览器、代理、CDN 均不得存储响应
# 'no-store' 是最严格的缓存控制指令
add_header Cache-Control "no-store" always;
}客户端缓存配置(控制浏览器)
通过在HTTP响应中添加Cache-Control和Expires头,控制用户浏览器的缓存行为。此模式旨在减少网络请求,加速终端用户访问。
核心指令
expires指令:用于同时设置Expires和Cache-Control的max-age。语法:
expires [time|epoch|max|off];示例:
expires 30d;(缓存 30 天),expires -1;(强制客户端在使用缓存前向服务器验证资源有效性(等效于Cache-Control: no-cache),但允许缓存存储。)。注意:
add_header指令提供更精细的控制,是推荐的配置方式。
add_header指令:向响应中添加指定的HTTP头。语法:
add_header <name> <value> [always];always参数说明
- 默认情况下,add_header仅对2xx和3xx响应生效。 - 对于304 Not Modified响应,Nginx不会自动添加自定义头。虽然浏览器会沿用首次200响应的缓存策略,但为确保明确性和兼容性,建议在缓存控制头中添加always参数,使其对所有响应状态码生效。
Cache-Control关键值说明
public:响应可以被任何缓存(浏览器、CDN、代理服务器)缓存。private:仅允许最终用户的浏览器缓存,禁止共享缓存(如 CDN)。适用于包含用户特定信息的内容。no-cache:要求客户端在每次使用缓存副本前,都必须向服务器发送请求验证其有效性。如果资源未变更,服务器返回304 Not Modified,客户端使用本地缓存,节省带宽。no-store:禁止浏览器和代理服务器存储该响应的任何部分。适用于高度敏感的数据。max-age=<seconds>:设置缓存的有效时间,单位为秒。immutable:告知浏览器该资源内容在有效期内不会改变。在用户刷新页面时,浏览器可跳过对此资源的验证请求。适合带哈希值的文件。
部署与验证
编辑配置
将location块添加到站点的server块中(配置文件通常位于/etc/nginx/conf.d/或/etc/nginx/sites-enabled/)。重载配置
sudo nginx -t && sudo nginx -s reload验证响应头
使用curl检查缓存头是否生效(不受浏览器缓存影响):curl -I http://your-domain.com/path/to/file.js应包含如
Cache-Control: public, max-age=31536000等预期头。验证304行为(如配置了ETag或no-cache)
手动携带验证头测试:ETAG=$(curl -I http://example.com/file.js 2>/dev/null | grep -i etag | cut -d' ' -f2 | tr -d '\r') curl -H "If-None-Match: $ETAG" -I http://example.com/file.js # 期望返回 304浏览器验证
开发者工具 → Network 面板
勾选Disable cache:查看首次加载(应为 200)
取消勾选后刷新:
无请求或显示
(from cache)→ 强缓存命中显示
304→ 协商缓存命中
常见问题
配置修改后未生效
原因:
未执行
sudo nginx -s reload浏览器、CDN 或代理缓存了旧响应。
location匹配优先级问题
解决:
用
curl -I http://your-url验证服务器实际响应头检查
location顺序:正则匹配(如~* \.(css|js)$)优先级高于前缀匹配(如/static/),会导致请求被正则规则匹配而未命中前缀匹配的问题。
动态内容被错误缓存
原因:静态资源正则过于宽泛(如 ~* \.js$ 匹配了 /api/user.js)
解决:
限定路径:
location ~* ^/static/.*\.(css|js)$确保动态接口(如
/api/、\.php$)的location优先匹配或明确排除缓存
多个缓存策略冲突
原因:多个
location匹配同一请求,仅第一个生效解决:合并策略,使用
map按内容类型动态设置缓存:# 在 http 块中 map $sent_http_content_type $cache_control { ~^image/ "public, max-age=2592000"; text/css "public, max-age=2592000"; application/javascript "public, max-age=2592000"; default "no-cache"; } # 在 server 块中 add_header Cache-Control $cache_control always;