10.4.4 图片如何加速访问——静态资源:缓存策略与 CDN 集成
静态资源不走应用服务器,Nginx 直接返回最快。
静态资源分类
| 类型 | 示例 | 缓存策略 |
|---|---|---|
| 带 hash 的文件 | main.abc123.js | 永久缓存 |
| 不带 hash 的文件 | logo.png | 短期缓存 |
| HTML 文件 | index.html | 不缓存/短期 |
Nginx 静态资源配置
基础配置
nginx
server {
listen 80;
server_name www.example.com;
# Next.js 静态资源
location /_next/static/ {
alias /var/www/app/.next/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
# 公共资源
location /public/ {
alias /var/www/app/public/;
expires 7d;
}
# 其他请求代理到应用
location / {
proxy_pass http://127.0.0.1:3000;
}
}缓存控制头
nginx
# 永久缓存(带 hash 的文件)
location ~* \.(js|css)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 中期缓存
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
expires 30d;
add_header Cache-Control "public";
}
# 短期缓存
location ~* \.(html|json)$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}Gzip 压缩
nginx
http {
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
}| 配置 | 作用 |
|---|---|
gzip on | 启用压缩 |
gzip_vary | 添加 Vary: Accept-Encoding |
gzip_min_length | 最小压缩大小 |
gzip_types | 压缩的 MIME 类型 |
CDN 集成
CDN 原理
配置 CDN 回源
- 在云服务商创建 CDN 加速域名(如
cdn.example.com) - 配置回源地址为
origin.example.com - 在 Nginx 配置回源域名:
nginx
server {
listen 80;
server_name origin.example.com;
location / {
root /var/www/static;
expires 1y;
}
}前端使用 CDN
javascript
// next.config.js
module.exports = {
assetPrefix: process.env.NODE_ENV === 'production'
? 'https://cdn.example.com'
: '',
}对象存储 + CDN
将静态资源存储到 OSS/COS,通过 CDN 加速:
优势
| 对比项 | 服务器存储 | OSS + CDN |
|---|---|---|
| 存储成本 | 高 | 低 |
| 扩容 | 需要升级磁盘 | 自动 |
| 访问速度 | 受服务器带宽限制 | 全国节点加速 |
| 可用性 | 依赖服务器 | 99.99%+ |
上传到 OSS 示例
typescript
// NestJS 上传服务
import * as OSS from 'ali-oss';
const client = new OSS({
region: 'oss-cn-hangzhou',
accessKeyId: process.env.OSS_ACCESS_KEY_ID,
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
bucket: 'my-bucket',
});
async function uploadFile(file: Express.Multer.File) {
const result = await client.put(`uploads/${file.originalname}`, file.buffer);
return result.url; // 返回 CDN 地址
}缓存策略最佳实践
Next.js 静态资源
nginx
# _next/static 目录下的文件都带有 hash,可以永久缓存
location /_next/static/ {
alias /var/www/.next/static/;
expires max;
add_header Cache-Control "public, max-age=31536000, immutable";
}
# _next/image 图片优化
location /_next/image {
proxy_pass http://127.0.0.1:3000;
proxy_cache_valid 200 60m;
}版本化资源
html
<!-- 带版本号的资源引用 -->
<link rel="stylesheet" href="/css/style.css?v=1.0.0">
<script src="/js/app.js?v=1.0.0"></script>监控与调优
查看缓存命中率
nginx
# 添加缓存状态头
add_header X-Cache-Status $upstream_cache_status;缓存状态值
| 状态 | 含义 |
|---|---|
| HIT | 缓存命中 |
| MISS | 缓存未命中 |
| EXPIRED | 缓存已过期 |
| BYPASS | 跳过缓存 |
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 资源更新后用户看不到 | 浏览器缓存 | 使用文件名 hash |
| CDN 不更新 | CDN 缓存未刷新 | 手动刷新 CDN 缓存 |
| 图片加载慢 | 图片太大 | 压缩图片、使用 WebP |
| CORS 错误 | CDN 未配置跨域 | 添加 Access-Control-Allow-Origin |
