Nginx 静态站缓存策略:hash 文件长缓存,HTML 不缓存
一份可以直接抄的配置
静态站的缓存策略只有两条规则,但顺序和写法都很容易错。
规则本身
# 带 hash 的构建产物:内容变了文件名就变,可以永久缓存
location /_astro/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML:文件名不变但内容会变,不能缓存
location / {
expires -1;
add_header Cache-Control "no-cache";
}
为什么这么配
关键在于两种资源的变更方式不同:
| 资源 | 文件名 | 内容变化时 | 缓存策略 |
|---|---|---|---|
/_astro/main.abc123.js | 变了 | 变了 | 永久缓存 |
/index.html | 不变 | 变了 | 必须回源校验 |
文件名变了,旧缓存自然失效,不需要手动清理。文件名不变但内容变了,如果缓存了,访客就会一直看到旧版本——这就是「我明明发了文章,为什么没人看到」的原因。
immutable 是关键
add_header Cache-Control "public, immutable";
immutable 告诉浏览器:即使用户按了刷新,也不要发条件请求去问服务器。配合 hash 文件名,这是安全且激进的。
压缩也要配
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
text/plain text/css text/xml
application/javascript application/json
application/rss+xml image/svg+xml;
gzip_min_length 1024 很必要——小文件压缩后可能更大,反而浪费。
如果服务器支持,Brotli 比 gzip 再好 15% 左右。
三个容易漏的细节
1. server_tokens off —— 不要暴露 Nginx 版本号
2. 安全响应头 —— 静态站也要加:
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
3. 404 指向自定义页
error_page 404 /404.html;
location = /404.html { internal; }
internal 防止用户直接访问这个页面被当成正常内容。
一个完整的最简配置
server {
listen 80;
server_name example.com;
root /usr/share/nginx/html;
server_tokens off;
charset utf-8;
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
location /_astro/ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
location / {
expires -1;
add_header Cache-Control "no-cache";
}
error_page 404 /404.html;
location = /404.html { internal; }
add_header X-Content-Type-Options "nosniff" always;
}
判断缓存配得对不对有个简单方法:发一篇新文章,等 30 秒刷新——应该能立刻看到。看不到就是 HTML 被缓存了。