Skip to content
/ Blogs/CDN 容灾
11/5/2024
3.5m
AI 摘要

本文介绍了 CDN 容灾方案,涵盖 JS、CSS、图片、Ajax 等资源的容灾策略,如使用 onerror 事件替换备用 HOST、重写 Image 构造函数、Axios 拦截器重试等。并提供了一个 mermaid 流程图,展示容灾处理逻辑。

CDN 容灾

CDN(Content Delivery Network),即内容分发网络。

CDN 是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN 的关键技术主要有内容存储和分发技术。

不同资源的容灾方案

JS

对于直接放在 HTML 中的 script 标签,可以通过 onerror 事件来捕获错误,并更换 src 属性为备用 HOST 的 URL。

<body>
    <script>
        function handleError(e) {
            console.error('Script load failed', e.srcElement);
            e.srcElement.src = /* 使用备用 HOST 的 URL */'';
        }
    </script>
    <!-- 直接放在 HTML 中的 script 标签 -->
    <script src="https://example.com/nonexistent-script.js" onerror="handleError(event)"></script>
</body>

<!-- 或者 -->
<script>
  document.addEventListener('DOMContentLoaded', function() {
    var scripts = document.getElementsByTagName('script');

    for (var i = 0; i < scripts.length; i++) {
      scripts[i].addEventListener('error', function () {
        console.error('Script load failed:', this.src)
        this.src = /* 使用备用 HOST 的 URL */''
      })
    }
  })
</script>

对于动态插入的 JS 文件,可以通过 onerror 事件来捕获错误,并更换 src 属性为备用 HOST 的 URL。

function loadScript(url, callback) {
  const script = document.createElement('script')
  script.type = 'text/javascript'
  script.src = url

  script.onload = function () {
    callback(null) // 加载成功
  }

  script.onerror = function () {
    script.src = /* 使用备用 HOST 的 URL */''
  }

  document.head.appendChild(script)
}

loadScript('https://example.com/script.js')

CSS

同上面 JS 的容灾方案。

图片

同上面 JS 的容灾方案,支持 new Image() 的方式:

const OriginalImage = Image

// 重写 Image 构造函数
window.Image = function () {
  const img = new OriginalImage()

  img.onerror = function () {
    // 更换 src 属性为备用 HOST 的 URL
    this.src = /* 使用备用 HOST 的 URL */''
  }

  return img
}

Ajax

针对于请求的重试,需要统一请求的方式,使用封装好的 axios 或者 fetch 请求,例如,在 axios,针对请求失败后更换域名的重试如下:

// 添加一个响应拦截器
instance.interceptors.response.use(null, (error) => {
  const originalRequest = error.config

  // 如果请求失败并且响应状态码为 500 或者 503
  if (error.response.status === 500 || error.response.status === 503) {
    // 更换域名
    originalRequest.baseURL = 'https://new-domain.com'

    // 重试请求
    return instance(originalRequest)
  }

  return Promise.reject(error)
})

CSS / Style 中的资源

例如字体,背景图等,思路为:

  • 为 link 标签添加 crossorigin 属性,允许跨域资源可读;
  • 定时轮询新增的样式表(document.stylesheets)
  • 更换样式表中 url() 函数的CDN异常域名,在样式表尾部追加样式规则覆盖。

具体方案

服务
CDN 服务
调度域名组
HTML
HTML
页面加载
资源异常
成功
失败
资源异常事件监听
静态 websdk 初始化
域名是否在可替换域名列表中?
日志上报结果
更换域名, 重试
是否最大重试次数?
CDN SDK
CDN 调度服务
Gateway
容器部署
前端

Released under the MIT License.