计算机网络学习指南计算机网络学习指南
首页
基础教程
进阶内容
实战案例
编程指南
首页
基础教程
进阶内容
实战案例
编程指南
  • 进阶内容

    • 🚀 进阶内容
    • 🎯 学习目标
    • 🚀 学习路线
    • 📊 章节概览
  • 💡 学习建议
  • 🎓 学完之后
  • 第1章 - TCP 三次握手与四次挥手
  • 第2章 - 负载均衡原理
  • 第3章 - CDN 内容分发网络
  • 第4章 - VPN 与代理
  • 第5章 - 网络安全基础

第3章 - CDN 内容分发网络

嗨,朋友!

你有没有想过,为什么你在中国访问美国的网站会很慢,但访问淘宝、B站却很快?为什么大公司都要用 CDN?今天我们就来揭开 CDN(Content Delivery Network,内容分发网络) 的神秘面纱!

CDN 不仅是加速网站的利器,也是前端开发、运维工程师必须掌握的重要技术。

🤔 什么是 CDN?

生活中的类比

想象一下,你在成都想买一本书:

没有 CDN:

成都的你 → (寄快递到北京总仓库) → 等待3天 → 收到书 😫

有了 CDN:

成都的你 → (直接去成都本地书店) → 立即买到 😊
              (就近原则,速度快!)

CDN 就像是在全国各地开设了许多"分店",用户可以从最近的"分店"获取内容,大大提高了速度。

正式定义

定义

CDN 是一种通过在全球各地部署边缘服务器,将网站内容缓存到离用户最近的节点,从而加速内容传输的网络架构。

核心思想:

  • 🌍 就近访问:用户从最近的服务器获取内容
  • 💾 内容缓存:静态资源缓存在边缘节点
  • 🚀 减轻负载:降低源站服务器压力
  • 📡 智能路由:自动选择最佳路径

🏗️ CDN 的工作原理

传统方式 vs CDN 方式

传统方式:

北京用户 ──────────────→ 美国源站服务器
上海用户 ──────────────→ 美国源站服务器  (都要跨洋访问,慢!)
广州用户 ──────────────→ 美国源站服务器

使用 CDN:

北京用户 → 北京CDN节点 ↘
上海用户 → 上海CDN节点 → 美国源站服务器 (只有CDN节点访问源站)
广州用户 → 广州CDN节点 ↗     (用户访问就近节点,快!)

CDN 访问流程详解

假设用户访问 https://cdn.example.com/images/logo.png

第1步:用户发起请求

用户浏览器请求: https://cdn.example.com/images/logo.png

第2步:DNS 解析

浏览器 → 本地 DNS → CDN DNS 服务器
                  ↓
          返回最近的 CDN 节点 IP
          (比如北京用户返回北京节点 IP)

第3步:访问 CDN 节点

用户 → 北京CDN节点
         |
         ├─ 缓存命中? → 是 → 直接返回 ✅ (最快)
         └─ 缓存未命中? → 否 → 回源站获取 → 缓存 → 返回

第4步:内容返回

北京CDN节点 → 用户浏览器 → 显示图片

流程图

┌──────────┐
│ 用户请求  │
└─────┬────┘
      ↓
┌─────────────┐
│  DNS 解析    │ → 返回最近的 CDN 节点
└─────┬───────┘
      ↓
┌─────────────┐
│  CDN 节点    │
└─────┬───────┘
      ↓
   缓存命中?
   ↙      ↘
 是         否
  ↓          ↓
直接返回   回源获取
            ↓
         缓存并返回

🎯 CDN 的核心技术

1. 智能 DNS 调度

CDN 的 DNS 服务器会根据用户的位置、网络状况等因素,返回最优的节点 IP。

调度策略:

  • 地理位置: 返回离用户最近的节点
  • 网络状况: 选择网络延迟最低的节点
  • 负载均衡: 避免某个节点过载
  • 健康检查: 排除故障节点

2. 缓存策略

CDN 节点如何决定缓存什么内容,缓存多久?

Cache-Control 响应头:

Cache-Control: max-age=3600  # 缓存1小时
Cache-Control: no-cache      # 每次都要验证
Cache-Control: no-store      # 不缓存
Cache-Control: public        # 可以被CDN缓存
Cache-Control: private       # 不能被CDN缓存(只能浏览器缓存)

示例:

HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: public, max-age=86400
Expires: Thu, 31 Dec 2024 23:59:59 GMT
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

3. 缓存更新机制

问题: 如果源站内容更新了,CDN 缓存还是旧的怎么办?

解决方案:

方案1: 版本号/哈希值(推荐)

<!-- 旧版本 -->
<script src="/js/app.js?v=1.0.0"></script>

<!-- 新版本(URL变了,自动失效) -->
<script src="/js/app.js?v=1.0.1"></script>

或者使用文件哈希:

<script src="/js/app.a3f2d9e1.js"></script>

方案2: 手动刷新缓存

# 阿里云 CDN 刷新
aliyun cdn RefreshObjectCaches --ObjectPath https://cdn.example.com/app.js

# 腾讯云 CDN 刷新
tccli cdn PurgeUrlsCache --Urls '["https://cdn.example.com/app.js"]'

方案3: ETag 验证

# CDN 向源站验证
GET /app.js HTTP/1.1
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

# 如果未修改,源站返回
HTTP/1.1 304 Not Modified

# 如果已修改,返回新内容
HTTP/1.1 200 OK
ETag: "new-hash-value"

🌍 CDN 的节点分布

全球 CDN 节点示意

北美区域:
├─ 美国西海岸 (洛杉矶、旧金山)
├─ 美国东海岸 (纽约、华盛顿)
└─ 加拿大 (多伦多、温哥华)

欧洲区域:
├─ 英国 (伦敦)
├─ 德国 (法兰克福)
└─ 法国 (巴黎)

亚太区域:
├─ 中国 (北京、上海、深圳、成都...)
├─ 日本 (东京、大阪)
├─ 新加坡
└─ 澳大利亚 (悉尼)

国内 CDN 节点覆盖

一线城市: 北京、上海、广州、深圳 (节点最多)
二线城市: 成都、杭州、武汉、西安...
三线城市: 各省会城市
运营商: 电信、联通、移动 (多线路覆盖)

💻 CDN 在前端开发中的应用

1. 静态资源加速

典型使用场景:

<!DOCTYPE html>
<html>
<head>
    <!-- CSS 使用 CDN -->
    <link rel="stylesheet" href="https://cdn.example.com/css/style.css">
</head>
<body>
    <!-- 图片使用 CDN -->
    <img src="https://cdn.example.com/images/logo.png" alt="Logo">
    
    <!-- JavaScript 库使用公共 CDN -->
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    
    <!-- 自己的 JS 文件使用自己的 CDN -->
    <script src="https://cdn.example.com/js/app.js"></script>
</body>
</html>

2. 使用公共 CDN 库

常用公共 CDN:

// jsDelivr (推荐,国内速度快)
https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js
https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js

// unpkg
https://unpkg.com/vue@3/dist/vue.global.js

// cdnjs
https://cdnjs.cloudflare.com/ajax/libs/vue/3.3.0/vue.global.min.js

// 国内 CDN
https://cdn.bootcdn.net/ajax/libs/vue/3.3.0/vue.global.min.js

优点:

  • ✅ 减少自己服务器带宽
  • ✅ 用户可能已经缓存过(加快加载)
  • ✅ CDN 节点多,速度快

3. 图片 CDN 优化

图片处理参数:

<!-- 原图 -->
<img src="https://cdn.example.com/photo.jpg">

<!-- 缩略图 (通过 CDN 参数) -->
<img src="https://cdn.example.com/photo.jpg?w=200&h=200&q=80">

<!-- 阿里云 OSS 图片处理 -->
<img src="https://cdn.example.com/photo.jpg?x-oss-process=image/resize,w_200,h_200">

<!-- 七牛云图片处理 -->
<img src="https://cdn.example.com/photo.jpg?imageView2/1/w/200/h/200">

响应式图片:

<picture>
  <!-- 小屏幕用小图 -->
  <source media="(max-width: 768px)" 
          srcset="https://cdn.example.com/photo.jpg?w=400">
  
  <!-- 大屏幕用大图 -->
  <source media="(min-width: 769px)" 
          srcset="https://cdn.example.com/photo.jpg?w=1200">
  
  <!-- 默认图片 -->
  <img src="https://cdn.example.com/photo.jpg" alt="Photo">
</picture>

4. Webpack 配置 CDN

配置示例:

// webpack.config.js
module.exports = {
  output: {
    publicPath: 'https://cdn.example.com/',  // CDN 域名
  },
  
  // 外部依赖(不打包,使用 CDN)
  externals: {
    vue: 'Vue',
    axios: 'axios',
    'element-plus': 'ElementPlus'
  },
  
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      cdn: {
        css: [
          'https://cdn.jsdelivr.net/npm/element-plus/dist/index.css'
        ],
        js: [
          'https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js',
          'https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js',
          'https://cdn.jsdelivr.net/npm/element-plus'
        ]
      }
    })
  ]
};

HTML 模板:

<!DOCTYPE html>
<html>
<head>
  <!-- 插入 CDN CSS -->
  <% for (var i in htmlWebpackPlugin.options.cdn.css) { %>
  <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>">
  <% } %>
</head>
<body>
  <div id="app"></div>
  
  <!-- 插入 CDN JS -->
  <% for (var i in htmlWebpackPlugin.options.cdn.js) { %>
  <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
  <% } %>
</body>
</html>

🔧 如何配置和使用 CDN

步骤1: 选择 CDN 服务商

国内主流 CDN:

服务商特点适用场景
阿里云 CDN节点多,功能全企业应用
腾讯云 CDN性价比高中小企业
百度云 CDN与百度生态集成百度系产品
七牛云对象存储+CDN图片/视频网站
又拍云专注存储和CDN图片/视频网站
网宿科技老牌CDN大型企业

国际 CDN:

  • Cloudflare: 全球覆盖,有免费套餐
  • AWS CloudFront: 与 AWS 生态集成
  • Fastly: 高性能,实时刷新

步骤2: 配置域名

2.1 添加加速域名

源站域名: www.example.com
CDN 域名: cdn.example.com
源站地址: origin.example.com 或 123.45.67.89

2.2 配置 CNAME

CDN 服务商会给你一个 CNAME 记录:

cdn.example.com.cdn.aliyuncs.com

在 DNS 服务商添加 CNAME 记录:

主机记录: cdn
记录类型: CNAME
记录值: cdn.example.com.cdn.aliyuncs.com

2.3 配置缓存规则

# 图片缓存 30 天
/images/* → Cache-Control: max-age=2592000

# CSS/JS 缓存 7 天
/css/* → Cache-Control: max-age=604800
/js/* → Cache-Control: max-age=604800

# HTML 不缓存
/*.html → Cache-Control: no-cache

# API 不缓存
/api/* → Cache-Control: no-store

步骤3: 上传资源

方式1: 手动上传

# 使用阿里云 OSS 工具
ossutil cp -r ./dist/ oss://my-bucket/

# 使用七牛云工具
qshell qupload config.json

方式2: CI/CD 自动部署

# GitHub Actions 示例
name: Deploy to CDN

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Build
        run: |
          npm install
          npm run build
      
      - name: Upload to OSS
        uses: manyuanrong/setup-ossutil@v2.0
        with:
          endpoint: oss-cn-beijing.aliyuncs.com
          access-key-id: ${{ secrets.OSS_ACCESS_KEY }}
          access-key-secret: ${{ secrets.OSS_SECRET_KEY }}
      
      - name: Deploy
        run: |
          ossutil cp -r ./dist/ oss://my-cdn-bucket/ --update
      
      - name: Refresh CDN
        run: |
          aliyun cdn RefreshObjectCaches --ObjectPath https://cdn.example.com/

📊 CDN 性能优化

1. 合理设置缓存时间

// Express.js 设置响应头
app.use('/static', express.static('public', {
  maxAge: '1d',  // 静态资源缓存 1 天
  setHeaders: (res, path) => {
    if (path.endsWith('.html')) {
      res.setHeader('Cache-Control', 'no-cache');  // HTML 不缓存
    } else if (path.match(/\.(jpg|jpeg|png|gif|svg)$/)) {
      res.setHeader('Cache-Control', 'public, max-age=2592000');  // 图片缓存 30 天
    } else if (path.match(/\.(css|js)$/)) {
      res.setHeader('Cache-Control', 'public, max-age=604800');  // CSS/JS 缓存 7 天
    }
  }
}));

2. 开启 Gzip 压缩

# Nginx 配置
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_min_length 1000;  # 小于 1KB 的文件不压缩
gzip_comp_level 6;     # 压缩级别 1-9,6 是性价比最好的

3. HTTP/2 加速

# Nginx 启用 HTTP/2
server {
    listen 443 ssl http2;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
}

HTTP/2 优势:

  • ✅ 多路复用(一个连接处理多个请求)
  • ✅ 头部压缩
  • ✅ 服务器推送

4. 图片格式优化

<!-- 使用现代图片格式 -->
<picture>
  <!-- WebP 格式(体积小 30%) -->
  <source type="image/webp" srcset="photo.webp">
  
  <!-- AVIF 格式(体积更小) -->
  <source type="image/avif" srcset="photo.avif">
  
  <!-- 传统格式(兜底) -->
  <img src="photo.jpg" alt="Photo">
</picture>

5. 预连接优化

<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="https://cdn.example.com">

<!-- 预连接(DNS + TCP + TLS) -->
<link rel="preconnect" href="https://cdn.example.com">

<!-- 预加载关键资源 -->
<link rel="preload" href="https://cdn.example.com/app.js" as="script">

🔍 CDN 故障排查

问题1: CDN 缓存没生效

排查步骤:

# 1. 检查响应头
curl -I https://cdn.example.com/app.js

# 查看是否有 CDN 标识
X-Cache: HIT      # 缓存命中
X-Cache: MISS     # 缓存未命中
Age: 3600         # 缓存了 1 小时

# 2. 检查 Cache-Control
Cache-Control: public, max-age=86400

解决方案:

  • 确认源站设置了正确的 Cache-Control
  • 检查 CDN 配置的缓存规则
  • 手动刷新 CDN 缓存

问题2: 跨域问题

错误信息:

Access to fetch at 'https://cdn.example.com/api/data' from origin 
'http://localhost:3000' has been blocked by CORS policy

解决方案:

// Express.js 源站配置
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

或在 CDN 配置中添加 CORS 头。

问题3: 内容未更新

排查:

# 检查文件 ETag
curl -I https://cdn.example.com/app.js | grep ETag

# 对比源站和 CDN 的 ETag
curl -I https://origin.example.com/app.js | grep ETag

解决:

  1. 使用版本号: app.js?v=1.0.1
  2. 手动刷新 CDN 缓存
  3. 使用文件哈希: app.a3f2d9e1.js

💡 学习建议

1. 理解缓存机制 🧠

深入理解 HTTP 缓存头:

  • Cache-Control
  • Expires
  • ETag
  • Last-Modified

2. 实践为主 💻

  • 注册一个免费的 CDN 服务(如 Cloudflare)
  • 部署一个静态网站到 CDN
  • 对比使用 CDN 前后的加载速度

3. 监控和优化 📊

  • 使用浏览器开发者工具查看资源加载
  • 使用 GTmetrix、WebPageTest 测试网站性能
  • 关注 CDN 命中率、带宽使用情况

📝 练习题

基础题

  1. CDN 的主要作用是什么?它解决了什么问题?
点击查看答案

主要作用:

  1. 加速访问: 用户从最近的节点获取内容,减少延迟
  2. 减轻源站压力: 大部分请求被 CDN 分担
  3. 提高可用性: 多节点容灾
  4. 降低带宽成本: 减少源站带宽消耗

解决的问题:

  • 跨地域访问慢
  • 源站带宽和性能瓶颈
  • 高并发场景下的稳定性
  • 网络抖动和故障的影响
  1. CDN 的访问流程是怎样的?
点击查看答案
  1. 用户请求: 浏览器请求资源
  2. DNS 解析: CDN DNS 返回最近节点 IP
  3. 访问 CDN 节点:
    • 缓存命中 → 直接返回
    • 缓存未命中 → 回源获取 → 缓存 → 返回
  4. 内容返回: 用户收到资源

进阶题

  1. 如何解决 CDN 缓存更新的问题?列举至少三种方案。
点击查看答案

方案1: 版本号/哈希值(推荐)

<!-- 修改 URL,自动失效旧缓存 -->
<script src="/app.js?v=1.0.1"></script>
<script src="/app.a3f2d9e1.js"></script>

优点: 最可靠,前端控制 缺点: 需要修改 HTML

方案2: 手动刷新缓存

aliyun cdn RefreshObjectCaches --ObjectPath https://cdn.example.com/app.js

优点: 灵活 缺点: 需要手动操作,有时间延迟

方案3: 短缓存时间

Cache-Control: max-age=300  # 只缓存 5 分钟

优点: 自动更新 缺点: CDN 效果打折扣

方案4: ETag 验证

ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Cache-Control: must-revalidate

优点: 自动检测更新 缺点: 仍需请求验证

  1. 在前端项目中如何配置 CDN?写出 Webpack 配置示例。
点击查看答案
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'production',
  
  output: {
    filename: 'js/[name].[contenthash:8].js',
    publicPath: 'https://cdn.example.com/',  // CDN 域名
    clean: true
  },
  
  // 外部依赖(使用 CDN,不打包)
  externals: {
    vue: 'Vue',
    'vue-router': 'VueRouter',
    axios: 'axios'
  },
  
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
      cdn: {
        css: [
          'https://cdn.jsdelivr.net/npm/element-plus/dist/index.css'
        ],
        js: [
          'https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js',
          'https://cdn.jsdelivr.net/npm/vue-router@4/dist/vue-router.global.prod.js',
          'https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'
        ]
      }
    })
  ]
};
<!-- public/index.html -->
<!DOCTYPE html>
<html>
<head>
  <% for (var i in htmlWebpackPlugin.options.cdn.css) { %>
  <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>">
  <% } %>
</head>
<body>
  <div id="app"></div>
  
  <% for (var i in htmlWebpackPlugin.options.cdn.js) { %>
  <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
  <% } %>
</body>
</html>

🎓 下一步学习

恭喜你!现在你已经掌握了 CDN 的核心概念和实践技巧。

建议继续学习:

  • 第4章 - VPN 与代理 - 了解网络访问控制
  • 第2章 - 负载均衡原理 - CDN 也是一种负载均衡
  • 实战案例 - 前端开发中的网络应用 - CDN 在实际项目中的应用

推荐阅读:

  • HTTP 缓存机制详解
  • 各大 CDN 服务商官方文档
  • Web 性能优化最佳实践

关键概念回顾:

  • ✅ CDN 通过就近访问和内容缓存加速网站
  • ✅ 智能 DNS 调度返回最优节点
  • ✅ 缓存策略通过 Cache-Control 等响应头控制
  • ✅ 缓存更新推荐使用版本号/哈希值方案
  • ✅ 前端项目可以通过 Webpack 配置 CDN
  • ✅ 合理使用 CDN 可以大幅提升网站性能

返回进阶内容 | 下一章:VPN 与代理

最近更新: 2025/12/27 10:13
Contributors: 王长安
Prev
第2章 - 负载均衡原理
Next
第4章 - VPN 与代理