已激活ServiceWorker偶发不拦截请求导致接口返回401问题咨询
问题成因
- 核心竞态出在
clients.claim()的异步执行逻辑:ServiceWorker的active状态变为activated的时机是activate事件触发时,而你在activate事件中通过event.waitUntil()包裹的worker.clients.claim()是异步操作,该操作完成后SW才会真正接管当前页面的所有请求。你现有轮询逻辑仅校验到SW状态为activated就结束等待,没有确认页面已被SW接管,此时发出的请求不会被SW拦截,这是小概率401的根本原因。 - 浏览器特性限制:就算后续
claim()执行完成,在接管前已经发出的请求也不会被SW回溯处理,刚好小概率场景下API请求在claim()完成前触发,就会出现无X-SW头、无Authorization头的401问题。
修复方案
修改轮询判断逻辑,增加当前页面已被SW控制的校验条件,只有当SW激活且页面确实被接管后才结束初始化等待:
return pollUntil( (registration) => registration.active?.state === "activated" && navigator.serviceWorker.controller !== null, POLL_EVERY, // 40ms registration, POLL_TIMEOUT // 6000ms );
可选优化
如果要完全排除令牌存储的竞态风险,可以在ServiceWorker收到AUTH_TOKEN消息并完成IndexedDB存储后,向页面postMessage回复确认消息,页面收到确认消息后再resolveinitializeServiceWorker的Promise,进一步保证初始化流程的完整性。
内容的提问来源于stack exchange,提问作者0xc14m1z
相关产品推荐
相关产品推荐

