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

RxJava+Retrofit2中刷新Access Token后如何重试getdata方法?

处理Access Token过期自动刷新并重试请求的实现方案

这个场景在需要身份验证的应用里太常见了,我来分享一套实战中好用的实现思路,不管是前端浏览器环境还是Node后端都能适配:


核心思路

我们需要封装一个通用请求拦截层,自动处理Token过期的情况:

  1. 每次请求带上当前的Access Token
  2. 捕获Token过期的自定义错误
  3. 触发Refresh Token刷新逻辑(注意避免并发请求重复刷新)
  4. 更新并保存新的双Token
  5. 重试原本的请求

代码实现示例(JavaScript)

1. 初始化全局状态管理

先定义几个变量来管理Token状态和请求队列,避免重复刷新:

// 存储当前有效Token(可以从本地存储初始化,比如页面加载时读取localStorage)
let currentTokens = {
  accessToken: localStorage.getItem('accessToken') || '',
  refreshToken: localStorage.getItem('refreshToken') || ''
};
// 标记是否正在刷新Token,防止并发请求重复触发刷新
let isRefreshing = false;
// 存储等待刷新完成后重试的请求队列
let requestQueue = [];

2. 封装通用请求函数

所有业务请求都通过这个函数发起,自动处理Token校验:

async function makeRequest(url, options = {}) {
  // 给请求头添加身份验证信息
  const authHeaders = {
    Authorization: `Bearer ${currentTokens.accessToken}`
  };
  const mergedOptions = {
    ...options,
    headers: { ...options.headers, ...authHeaders }
  };

  try {
    const response = await fetch(url, mergedOptions);
    const responseData = await response.json();

    // 这里根据后端约定的错误标识判断Token过期,比如后端返回code: 10001
    if (response.status === 401 && responseData.code === 10001) {
      throw new Error('ACCESS_TOKEN_EXPIRED');
    }

    return responseData;
  } catch (error) {
    // 捕获到Token过期错误,进入刷新重试流程
    if (error.message === 'ACCESS_TOKEN_EXPIRED') {
      return handleTokenRefreshAndRetry(() => makeRequest(url, options));
    }
    // 其他错误直接抛出,交给业务层处理
    throw error;
  }
}

3. 实现Token刷新与请求重试逻辑

这个函数是核心,处理刷新Token和队列请求的重试:

async function handleTokenRefreshAndRetry(retryFn) {
  // 如果正在刷新,把当前请求加入队列等待
  if (isRefreshing) {
    return new Promise((resolve) => {
      requestQueue.push(() => resolve(retryFn()));
    });
  }

  isRefreshing = true;
  try {
    // 调用后端的refreshToken接口获取新Token
    const newTokens = await fetch('/api/refresh-token', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refreshToken: currentTokens.refreshToken })
    }).then(res => res.json());

    // 更新全局Token并保存到本地
    currentTokens = newTokens;
    localStorage.setItem('accessToken', newTokens.accessToken);
    localStorage.setItem('refreshToken', newTokens.refreshToken);

    // 刷新完成后,批量重试队列里的所有请求
    requestQueue.forEach(callback => callback());
    requestQueue = [];

    // 重试当前请求
    return retryFn();
  } catch (refreshError) {
    // 如果Refresh Token也失效了,直接引导用户重新登录
    console.error('Refresh Token已过期,请重新登录', refreshError);
    // 清空队列,避免后续请求一直等待
    requestQueue = [];
    // 这里可以跳转到登录页,或者抛出错误给业务层处理
    throw new Error('请重新登录');
  } finally {
    // 无论刷新成功失败,都要重置刷新状态
    isRefreshing = false;
  }
}

4. 业务请求封装(比如你的getdata方法)

业务层直接调用封装好的请求函数,不用关心Token逻辑:

async function getdata() {
  return makeRequest('/api/get-data');
}

// 使用示例
getdata()
  .then(data => console.log('数据获取成功:', data))
  .catch(err => console.error('请求失败:', err));

关键注意事项

  • 并发请求处理:通过isRefreshing锁和requestQueue,避免多个请求同时触发Refresh Token接口,减少无效请求。
  • Token存储安全:前端建议把Refresh Token存在HttpOnly Cookie中(防止XSS),Access Token存在内存里;后端可以把Token存在Redis等缓存中,设置对应过期时间。
  • 错误边界处理:一定要处理Refresh Token失效的情况,不能让请求无限等待,必须引导用户重新登录。
  • 自定义错误匹配:实际项目中要和后端约定好Token过期的错误标识,不要只依赖HTTP 401状态码(因为401可能还有其他场景,比如权限不足)。

内容的提问来源于stack exchange,提问作者JunDev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:19:06