You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 17:39:20