做前端项目的时候,经常听到"静态资源要放CDN"这种说法:
- CDN到底是什么,为什么能加速?
- 用户访问CDN的时候发生了什么?
- 前端项目怎么配置CDN?
先说结论
CDN(Content Delivery Network)的核心原理:把内容缓存到离用户最近的服务器上。
没有CDN时,北京用户访问美国服务器,数据要跨越太平洋。有了CDN,数据从北京的CDN节点返回,快得多。
CDN的工作流程
当用户访问一个CDN加速的资源时,会经过这几步:
1. DNS解析
用户访问 cdn.example.com,DNS会返回离用户最近的CDN节点IP。
bash
# 在北京查询
$ dig cdn.example.com
;; ANSWER SECTION:
cdn.example.com. 60 IN A 101.37.27.xxx # 北京节点
# 在上海查询
$ dig cdn.example.com
;; ANSWER SECTION:
cdn.example.com. 60 IN A 47.100.99.xxx # 上海节点
同一个域名,不同地区解析出不同IP,这就是CDN的智能调度。
2. 缓存判断
请求到达CDN节点后,节点检查本地是否有缓存:
- 缓存命中:直接返回,速度最快
- 缓存未命中:向源服务器获取,然后缓存起来
3. 缓存策略
CDN根据HTTP头决定怎么缓存:
http
# 典型的静态资源响应头
Cache-Control: public, max-age=31536000
ETag: "abc123"
Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
max-age=31536000:缓存1年public:允许CDN缓存ETag:文件指纹,用于验证缓存是否过期
为什么CDN能加速
1. 物理距离更近
光在光纤中的传播速度约为 20 万公里/秒。北京到美国往返 2 万公里,光传输就要 100ms。
CDN把内容放到离用户近的地方,这个延迟几乎可以忽略。
2. 分散服务器压力
没有CDN,所有请求都打到源服务器。有了CDN,只有第一次请求(缓存未命中)才需要回源。
假设一张图片被访问 100 万次:
- 没有CDN:源服务器处理 100 万次请求
- 有CDN:源服务器只处理几十次(各节点首次回源)
3. 边缘节点优化
CDN服务商的边缘节点通常有这些优化:
- 自动压缩:Gzip/Brotli压缩
- 协议优化:HTTP/2、HTTP/3
- 连接复用:Keep-Alive连接池
- 智能路由:选择最优网络路径
前端项目配置CDN
1. 构建配置
以Vite为例,配置静态资源的CDN地址:
javascript
// vite.config.js
export default defineConfig({
base: process.env.NODE_ENV === 'production'
? 'https://cdn.example.com/'
: '/',
build: {
rollupOptions: {
output: {
// 文件名带hash,便于长期缓存
entryFileNames: 'js/[name].[hash].js',
chunkFileNames: 'js/[name].[hash].js',
assetFileNames: 'assets/[name].[hash].[ext]'
}
}
}
})
Webpack配置类似:
javascript
// webpack.config.js
module.exports = {
output: {
publicPath: process.env.NODE_ENV === 'production'
? 'https://cdn.example.com/'
: '/',
filename: 'js/[name].[contenthash].js',
}
}
2. 上传到CDN
构建完成后,把dist目录的文件上传到CDN。大多数CDN服务商都提供CLI工具或API:
bash
# 阿里云OSS + CDN
aliyun oss cp -r ./dist oss://your-bucket/
# AWS S3 + CloudFront
aws s3 sync ./dist s3://your-bucket/
# 七牛云
qshell qupload2 --src-dir=./dist --bucket=your-bucket
3. 缓存策略配置
关键是区分两类文件:
带hash的静态资源(JS、CSS、图片):长期缓存
nginx
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
HTML文件:不缓存或短期缓存
nginx
location ~* \.html$ {
expires 0;
add_header Cache-Control "no-cache, must-revalidate";
}
为什么这样设计?因为HTML是入口文件,它引用的JS/CSS带有hash。更新代码时:
- 新的JS文件会有新的hash(
app.abc123.js→app.def456.js) - HTML文件引用新的JS文件
- 用户获取新HTML后,会加载新的JS文件
- 旧的JS文件在CDN上继续存在,不影响正在访问的用户
4. DNS配置
把CDN域名配置成CNAME指向CDN服务商:
bash
# 阿里云CDN
cdn.example.com. IN CNAME cdn.example.com.w.kunlunsl.com.
# Cloudflare
cdn.example.com. IN CNAME example.com.cdn.cloudflare.net.
常见问题
跨域问题
CDN域名和主域名不同,字体文件、AJAX请求可能遇到跨域。
解决方案是在CDN配置CORS头:
nginx
# CDN服务器配置
add_header Access-Control-Allow-Origin "https://example.com";
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS";
或者在源服务器的响应里加上CORS头,CDN会透传。
缓存更新问题
发布新版本后,用户还是看到旧内容?
方案一:文件名带hash(推荐)
前面已经提到,文件名带hash,新版本就是新文件,不存在缓存问题。
方案二:主动刷新缓存
javascript
// 调用CDN服务商的刷新API
await cdnClient.refreshObjectCaches({
ObjectPath: 'https://cdn.example.com/app.js\nhttps://cdn.example.com/app.css',
ObjectType: 'File'
});
方案三:URL加版本号
html
<script src="https://cdn.example.com/app.js?v=1.2.3"></script>
不太推荐,因为有些CDN会忽略查询参数。
HTTPS证书
CDN域名也需要HTTPS证书。大多数CDN服务商提供免费证书或支持上传自有证书。
配置方式:
- 在CDN控制台申请免费证书(通常是DV证书)
- 或上传自己的证书(用Let's Encrypt申请)
bash
# 用certbot申请泛域名证书
certbot certonly --manual --preferred-challenges dns \
-d "*.example.com" -d "example.com"
回源优化
如果源服务器压力大,可以启用"回源加速"或"中间源":
用户 → 边缘节点 → 中间源 → 源服务器
中间源作为二级缓存,减少对源服务器的请求。多数CDN服务商默认开启这个功能。
CDN选型
| CDN服务商 | 优势 | 适用场景 |
|---|---|---|
| 阿里云CDN | 国内节点多,生态完整 | 国内业务为主 |
| 腾讯云CDN | 游戏加速好,直播支持强 | 游戏、直播 |
| Cloudflare | 全球节点,有免费套餐 | 出海业务、个人项目 |
| AWS CloudFront | 与AWS生态集成 | 已用AWS的项目 |
| Vercel/Netlify | 前端项目一站式部署 | JAMStack项目 |
个人项目推荐Cloudflare,免费套餐够用,全球节点覆盖好。
企业项目根据用户分布选择。面向国内用户,阿里云/腾讯云更合适;面向全球用户,Cloudflare或CloudFront。
验证CDN效果
浏览器开发者工具
打开Network面板,关注这几个指标:
- TTFB(Time To First Byte):首字节时间,越小越好
- 响应头中的缓存信息 :
X-Cache: HIT表示命中CDN缓存
命令行测试
bash
# 查看响应头
curl -I https://cdn.example.com/app.js
# 输出示例
HTTP/2 200
cache-control: public, max-age=31536000
x-cache: HIT from CN-Beijing
在线工具
- Pingdom - 全球多点测速
- GTmetrix - 性能分析
- WebPageTest - 详细的加载瀑布图
小结
CDN加速的核心原理:
- 就近访问:DNS智能解析,把用户引导到最近的节点
- 缓存机制:边缘节点缓存内容,减少回源
- 协议优化:HTTP/2、压缩、连接复用
前端配置CDN的关键:
- 构建时配置publicPath:指向CDN域名
- 文件名带hash:便于长期缓存
- HTML不缓存:确保用户能获取到最新入口
- 处理跨域:配置CORS头
如果你觉得这篇文章有帮助,欢迎关注我的 GitHub,下面是我的一些开源项目:
Claude Code Skills (按需加载,意图自动识别,不浪费 token,介绍文章):
- code-review-skill - 代码审查技能,覆盖 React 19、Vue 3、TypeScript、Rust 等约 9000 行规则(详细介绍)
- 5-whys-skill - 5 Whys 根因分析,说"找根因"自动激活
- first-principles-skill - 第一性原理思考,适合架构设计和技术选型
全栈项目(适合学习现代技术栈):
- prompt-vault - Prompt 管理器,用的都是最新的技术栈,适合用来学习了解最新的前端全栈开发范式:Next.js 15 + React 19 + tRPC 11 + Supabase 全栈示例,clone 下来配个免费 Supabase 就能跑
- chat_edit - 双模式 AI 应用(聊天+富文本编辑),Vue 3.5 + TypeScript + Vite 5 + Quill 2.0 + IndexedDB