项目中前端如何实现无感刷新 token!

场景:线上平台有时会出现用户正在使用的时候,突然要用户去进行登录,这样会造成很不好的用户体验。 

1.请求采用的是axios

2.平台的采用的 JWT(JSON Web Tokens) 进行用户登录鉴权。

原因:

1.突然跳转到登录页面,是由于当前的 token 过期,导致请求失败;在 axios 的响应拦截axiosInstance.interceptors.response.use中处理失败请求返回的状态码 401,此时得知token失效,因此跳转到登录页面,让用户重新进行登录。

项目中前端如何实现无感刷新 token!_第1张图片

2.平台目前的逻辑是在 token 未过期内,用户登录平台可直接进入首页,无需进行登录操作;因此就存在该现象:用户打开平台,由于此时 token 未过期,用户直接进入到了首页,进行其他操作。但是在用户操作的过程中,token 突然失效了,此时就会出现突然跳转到登录页面,严重影响用户的体验感!

操作:

后台提供了两个参数accessToken(用于请求头中,进行鉴权,存在有效期)和refreshToken(刷新令牌,用于更新过期的 accessToken,相对于accessToken而言,他的时效期更长)

// 响应拦截
axiosInstance.interceptors.response.use(
  (response) => {
    return response;
  },
  (error) => {
    let {
      data, config
    } = error.response;
    return new Promise((resolve, reject) => {
      /**
       * 判断当前请求失败
       * 是否由 toekn 失效导致的
       */
      if (data.statusCode === 401) {
         /**
         * refreshToken 为封装的有关更新 token 的相关操作 
         */
        refreshToken(() => {
          resolve(axiosInstance(config));
        });
      } else {
        reject(error.response);
      }
    })
  }
)
  • 我们通过判断statusCode来确定,是否当前请求失败是由token过期导致的;
  • 使用 Promise 处理将失败的请求,将由于 token 过期导致的失败请求存储起来(存储的是请求回调函数,resolve 状态)。理由:后续我们更新了 token 后,可以将存储的失败请求重新发起,以此来达到用户无感的体验

封装 refreshToken 逻辑

  1. 存储由于token过期导致的失败的请求。
  2. 更新本地以及axios中头部的token
  3. 当 refreshToken 刷新令牌也过期后,让用户重新登录。
// 存储由于 token 过期导致 失败的请求
let expiredRequestArr: any[] = [];

/**
 * 存储当前因为 token 失效导致发送失败的请求
 */
const saveErrorRequest = (expiredRequest: () => any) => {
  expiredRequestArr.push(expiredRequest);
}

// 避免频繁发送更新 
let firstRequre = true;
/**
 * 利用 refreshToken 更新当前使用的 token
 */
const updateTokenByRefreshToken = () => {
  firstRequre = false;
  axiosInstance.post(
    '更新 token 的请求',
  ).then(res => {
    let {
      refreshToken, accessToken
    } = res.data;
    // 更新本地的token
    localStorage.setItem('accessToken', accessToken);
    // 更新请求头中的 token
    setAxiosHeader(accessToken);
    localStorage.setItem('refreshToken', refreshToken);

    /**
     * 当获取了最新的 refreshToken, accessToken 后
     * 重新发起之前失败的请求
     */
    expiredRequestArr.forEach(request => {
      request();
    })
    expiredRequestArr = [];
  }).catch(err => {
    console.log('刷新 token 失败err', err);
    /**
     * 此时 refreshToken 也已经失效了
     * 返回登录页,让用户重新进行登录操作
     */
    window.location.href = `${HOME_PAGE}/login`;
  })
}

/**
 * 更新当前已过期的 token
 * @param expiredRequest 回调函数,返回由token过期导致失败的请求
 */
export const refreshToken = (expiredRequest: () => any) => {
  saveErrorRequest(expiredRequest);
  if (firstRequre) {
    updateTokenByRefreshToken();
  }
}

你可能感兴趣的:(面试问题,前端,java,开发语言)