CDN监控和运行时切换
CDN 监控和运行时切换
CDN 是前端分发静态资源的重要工具,如果 CDN 出现问题会导致网页错乱,操作无法响应等问题。
在生产环境中也会收到用户的反馈网页错乱的问题,经排查都是用户无法访问 CDN 资源导致,以往此类问题都只能依赖用户自身去排查网络问题,效率较低。希望能找到一种方法能够快速帮助用户解决问题。
切换 CDN
我们同时采购了阿里云和网宿两家 CDN 服务商,目前测试下来两家服务商都无法保证百分百的可访问性。
最开始打算解决这个问题的时候,一开始想的是只要我们将页面上的 style 和 script 标签全部替换不就可以了么,但仔细一想这么做是远远不够的,因为我们的项目是使用 webpack 进行打包的,我们只修改了 html 中的页面入口 js,后续依赖的异步模块都是由 webpack 加载,我们没办法直接干涉。另外在 css 文件中依赖的图片资源地址也是无法动态进行修改的。
鉴于以上几个难点这个问题一直没能得到很好的解决,直到后来了解到了可以利用 webpack 的动态 publicPath 特性,总算找到了一个比较完美的解决方案。
On The Fly - 运行时
要解决问题的关键是要解决运行时的难题,否则就只能同时部署多套服务,分别对应不一样的 CDN,再为用户切换不同的服务来解决问题,成本太大。
关于运行时切换 Public Path 可参考: https://webpack.js.org/guides/public-path/#on-the-fly
除了加载 js 需要动态切换 CDN 域名,在 CSS 文件中加载图片等资源也需要切换,但 CSS 又不像 js 那样可以动态运行脚本轻松注入变量,可能 css 变量是一种方案,但操作起来也比较麻烦。所以这里利用了 CSS 加载时可以使用相对路径的方式,将静态资源连同 css 文件的地址一起切换即可。
完整方案
- 在 webpack 构建的应用入口最上方添加依赖文件 public-path.js(下方注意点!)
- 构建时将 public Path 设置成 /,目的是将 css 等构建时就生成的静态资源地址转换成相对路径。
- 收到请求时根据来源 ip 或者特定条件选择对应的 CDN。
- 输出 html 时将资源地址全部替换成特定的 CDN 地址。
- 输出 html 时添加 script 标签,在
window.__RUNTIME_PUBLIC_PATH__
上注入需要切换的 CDN 地址。
注意点!
public-path.js:此文件一定要放在入口最上方通过 import 引入,例如有如下入口文件:
1 |
|
public-path.js 代码为:
1 |
|
__webpack_public_path__
是 webpack 内置的全局变量,并不是 window 对象上的全局变量,外部只能通过 window 对象注入。
另外__RUNTIME_PUBLIC_PATH__
可以是 CDN 的域名,也可以直接配置成 /,从源站拉取静态资源,如果用户能看到页面错乱,那说明其能访问到源站的域名,那么将静态资源切换成源站地址可能是最稳妥的方式(只建议临时处理,不然会给源站服务器带来较大压力)
监控
需要监控 CDN 可用性,可以利用第三方平台,从全国范围内监控 CDN 的可用性和响应时间。
也可以通过脚本收集线上静态资源的加载情况判断 CDN 是否存在问题。
关于收集线上静态资源加载情况
由于业务 js 脚本本身就是放置在 CDN 上的,所以监控脚本只能以内联的方式写在 html 中。
上报函数代码如下:
1 |
|
注意点!
想要捕获全局资源加载错误,window.addEventListener("error", errorHandler, true)
第三个参数需要设置成 true,即采用捕获模式而不是冒泡模式。
另外有以下情况无法拦截到错误:
- 由于 css 是放在 header 中进行加载的,加载时间在执行 js 之前,如果在执行代码之前就加载失败就无法拦截到。但如果是异步加载的 css 就可以拦截到,只要是执行完 js 之后加载的资源就能够监控到。
- 如果是静态资源长时间 pending 的情况,也是不会触发 error 事件,而且由于资源加载往往超时时间非常地长,几十秒几分钟的情况也是胡出现的,这类情况也没办法很好地监控。
除了 css 和 js,该方法还可以会监控页面上的其他资源,包括图片资源的加载。