Safari中AbortController无法中止WebAuthn请求问题咨询
Safari下WebAuthn请求无法通过AbortController中止的解决方案
问题根源
尽管Safari官方标注支持AbortController,但它对WebAuthn API(navigator.credentials.create/get)的signal参数实现存在局限性:WebAuthn在Safari中唤起的是系统级认证弹窗,这类弹窗不受浏览器级的AbortSignal控制,因此调用abortController.abort()无法关闭弹窗或终止请求流程。
可行替代方案
1. 手动超时标记+结果过滤
既然无法直接中止系统弹窗,可通过标记超时状态,在认证完成后忽略超时产生的无效结果,并提示用户重新操作:
let isTimedOut = false; const abortTimer = setTimeout(() => { isTimedOut = true; alert('认证超时,请重新发起请求'); }, 5000); navigator.credentials .create({ publicKey }) .then((newCredInfo) => { clearTimeout(abortTimer); if (isTimedOut) return; // 直接忽略超时后的认证结果 const webAuthNResString = publicKeyCredentialToJSON(newCredInfo); submintWebAuthNData(webAuthNResString, 'create'); }) .catch((error) => { clearTimeout(abortTimer); if (isTimedOut) return; logger({ name: 'REGISTRATION_FAILED', error }); });
2. 浏览器环境检测+差异化处理
针对Safari单独做超时逻辑,非Safari环境继续使用AbortController:
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); let isTimedOut = false; const abortController = new AbortController(); const { signal } = abortController; const abortTimer = setTimeout(() => { if (isSafari) { isTimedOut = true; alert('认证超时,请重新发起请求'); } else { abortController.abort('ABORTED'); } }, 5000); navigator.credentials .create({ publicKey, signal }) .then((newCredInfo) => { clearTimeout(abortTimer); if (isTimedOut) return; const webAuthNResString = publicKeyCredentialToJSON(newCredInfo); submintWebAuthNData(webAuthNResString, 'create'); }) .catch((error) => { clearTimeout(abortTimer); if (isTimedOut || error.name === 'AbortError') return; logger({ name: 'REGISTRATION_FAILED', error }); });
额外注意事项
- Safari的WebAuthn弹窗属于系统级组件,无法通过JavaScript强制关闭,只能引导用户手动关闭后重新发起认证
- 可在
catch块中通过判断error.name区分普通错误和中止错误(仅非Safari环境生效)
内容的提问来源于stack exchange,提问作者Ghost
相关产品推荐
相关产品推荐

