博客最近经常出现部分地区CSS/JS资源异常,如何做异常检测和切换呢?
刚好之前处理过类似的冷门需求,🥶,简单记录一下。
回到这个问题,本质上是将异常的资源路径转发到可以正常访问的路径。
首先肯定是去检测异常资源有哪些
, 然后进行下一步转发
。
由此思考的两种浏览器客户端方案:
- Ajax 解析HTML,对资源进行替换转发。
- ServiceWorker 拦截路径转发。
第一种方案要考虑的点比较多,带来各种繁琐的正则,下面是一种使用 ServiceWorker 来实现代理的方案。
就不贴完整代码了,简单阐述下思路:
1 2 3 4 5 6 7
| # 页面注入的脚本 /** * 0. 检查是否安装SW、是否需要更新卸载SW * 1. 注入全局异常资源检测 * 2. 判断异常资源是否存在备用资源,缓存异常资源数据,并设置缓存过期机制,刷新数据 * 3. 是否需要激活SW进行异常资源转发,并刷新页面应用SW */
|
在SW脚本中,则是拦截 fetch
,在生命周期的钩子与页面脚本通信即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| # SW脚本 self.addEventListener('fetch',(event) => { // 获取并更新 caches 缓存 getData()
// TODO 清除缓存逻辑
const { FailedCDNs = [], BackCDNs = {} } = data || {} log('(Cache)', data)
const url = new URL(event.request.url) const domain = url.hostname; log(`(Fetch) ${domain} -- ${url}`)
if(FailedCDNs.includes(domain) && BackCDNs[domain]) { url.hostname = BackCDNs[domain]; log(`(Proxy) ${domain} -- ${url}`) if (!ProxyCDNS.includes(domain)) { ProxyCDNS.push(domain) setCacheShareData(ProxyCDNS) } event.respondWith(fetch(url)) } })
|
值得一提是的,页面与SW之前的通信,数据的缓存可以直接通过 caches
来进行串联。
下面是读取、写入 caches
的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| /** * 根据 Key 读取缓存 * @param key * @return {Promise<any>} */ async function getCacheShareData (key = 'C_KEY_2_SW') { return await caches.open(key).then(async cache => { const res = await cache.match('/C_DATA') const data = await res?.json() || {} return data }); }
/** * 写入缓存 * @param data * @param key */ function setCacheShareData (data, key = 'C_KEY_2_PAGE') { caches.open(key).then(cache => { cache.put('/C_DATA', new Response(JSON.stringify(data))) }) }
|