基于OkHTTP Interceptor的OTP无感重试方案优化问询
通用无感知OTP重试方案
针对你提到的业务场景(请求返回401时自动触发OTP验证,重试成功后继续原业务流程),下面是一套完全无需业务链路感知的实现方案,核心是将OTP处理逻辑完全封装在HTTP客户端层,业务页面/组件不需要做任何额外适配。
核心设计思路
把OTP的触发、验证、请求重试全流程,都交由HTTP客户端的拦截器统一处理,业务代码只需要关注原本的请求逻辑和成功/失败后的操作,完全感知不到OTP的存在。
具体实现步骤
1. 增强HTTP响应拦截器,接管401处理
拦截器在捕获到401响应时,先缓存原请求的完整上下文(URL、请求方法、headers、请求体、Promise状态),然后触发全局OTP弹窗,同时将原请求的Promise挂起,等待OTP验证结果。
2. 全局单例OTP弹窗组件
弹窗只负责收集用户输入的OTP码,不参与任何业务逻辑。提交OTP后,直接调用拦截器提供的重试方法,将OTP参数注入原请求后重试:
- 若重试仍返回401(OTP无效),弹窗自动提示错误并允许用户重新输入
- 若用户取消弹窗,直接终止原请求并抛出错误给业务层
3. 请求上下文缓存与结果回传
用全局缓存池(比如Map)存储挂起的请求上下文,重试成功后,将响应结果回传给原请求的Promise,让业务层继续执行原本的后续逻辑(比如页面跳转);重试失败则拒绝原Promise,触发业务层的错误处理逻辑。
4. 代码示例(基于Axios)
// 全局请求缓存池,存储挂起的请求上下文 const pendingRequests = new Map(); // Axios响应拦截器 axios.interceptors.response.use( response => response, async error => { const originalRequest = error.config; // 仅处理未标记过重试的401请求,避免循环重试 if (error.response?.status === 401 && !originalRequest._otpRetry) { originalRequest._otpRetry = true; const requestId = crypto.randomUUID(); // 缓存原请求的Promise回调 return new Promise((resolve, reject) => { pendingRequests.set(requestId, { resolve, reject, request: originalRequest }); // 触发全局OTP弹窗(这里假设你有全局弹窗组件) showGlobalOTPDialog({ onSubmit: async (otpCode) => { try { // 给原请求添加OTP验证参数 originalRequest.headers['X-OTP-Code'] = otpCode; // 重试原请求 const retryResponse = await axios(originalRequest); resolve(retryResponse); pendingRequests.delete(requestId); } catch (retryError) { // OTP无效,重新弹窗让用户输入 if (retryError.response?.status === 401) { showGlobalOTPDialog({ onSubmit: arguments.callee, errorMessage: 'OTP码无效,请重新输入' }); } else { // 其他错误,终止流程 reject(retryError); pendingRequests.delete(requestId); } } }, onCancel: () => { reject(new Error('用户取消OTP验证')); pendingRequests.delete(requestId); } }); }); } return Promise.reject(error); } );
业务层代码完全不需要修改,保持原有逻辑即可:
// 页面A的请求代码,无任何OTP相关处理 async function handleSubmit() { try { const res = await axios.post('/api/order/submit', formData); // 请求成功后的跳转逻辑,正常执行 navigate('/order-success'); } catch (err) { // 错误处理逻辑,正常执行 showToast(err.message); } }
方案优势
- 业务无侵入:页面组件不需要监听任何额外事件或维护状态,完全专注于自身业务逻辑
- 逻辑集中:所有OTP相关逻辑都封装在HTTP客户端层,便于统一修改和维护
- 避免竞态:全局单例弹窗和请求缓存池,可防止多个请求同时触发OTP弹窗的冲突问题
- 兼容性强:适配所有基于该HTTP客户端的请求,不管是页面组件还是独立API调用
内容的提问来源于stack exchange,提问作者pradyot1996
相关产品推荐
相关产品推荐

