ts 联合react 实现ajax的封装,refreshtoken的功能

react ts混合双打,实现ajax的封装,以及401的特殊处理

复制代码
import axios from 'axios'
import {
  AMDIN_EXPIRES_KEY,
  AMDIN_KEY,
  AMDIN_REFRESH_EXPIRES_KEY,
  AMDIN_REFRESH_KEY,
  COMMID_KEY,
  getToken,
  removeToken
} from '../utils/user-token'
import { showMessage } from '../utils/feedback'
import { fetchGetRefreshInfo } from './user'
import { setUserToken } from '../utils/public'
import router from '../router'

// 失败的fetch 集合
let isRefreshing = false
let failedQueue: any[] = []

// 创建一个axios实例
const instance = axios.create()

// 添加请求拦截器
instance.interceptors.request.use(
  (config: any) => {
    // 在发送请求之前做些什么
    const token = getToken(AMDIN_KEY)
    // if (token) {
    // config.headers.Authorization = `Bearer ${token}` // 将token设置到请求头中

    config.headers = {
      Authorization: `Bearer ${token}`,
      ...config.headers
    }
    // }
    return config
  },
  (error) => {
    // 对请求错误做些什么
    return Promise.reject(error)
  }
)

// 添加响应拦截器
instance.interceptors.response.use(
  async (res) => {
    const resData = (res.data || {}) as ResType
    // console.log('response - resData: ', resData)
    const { code, msg = '系统正在升级,稍后再试' } = resData

    if ((code) === 200) {
      return Promise.resolve(resData as any)
    } else {
      await showMessage(msg).then(() => {
        return Promise.reject(resData)
      })
    }
  },
  async (error) => {
    // 对响应错误做点什么
    // if (error.response && error.response.status === 401) {
    //   // 判断是否为401
    //   const refreshToken = getToken(AMDIN_REFRESH_KEY)
    //   if (refreshToken) {
    //     try {
    //       // 使用refreshToken请求新的token
    //       const res = await fetchGetRefreshInfo()
    //       // 将新的token保存到localStorage
    //       setUserToken(res.Data.token)
    //       // 用新的token重新发送失败的请求
    //       const config = error.config
    //       config.headers.Authorization = `Bearer ${getToken(AMDIN_KEY)}`
    //       return instance(config)
    //     } catch (err) {
    //       console.error('刷新token失败', err)
    //       // 刷新token失败,跳转到登录页等处理
    //       router.navigate(`/login?commId=${getToken(COMMID_KEY)}`, {
    //         replace: true
    //       })
    //     }
    //   }
    // }

    if (error.response && error.response.status === 401) {
      // 特殊处理 当RefreshToken 的接口401时候,及RefreshToken token的也过期了
      // 如果不处理,将会死循环
      if (error.response.config.url.indexOf('RefreshToken') > -1) {
        // 刷新token失败,跳转到登录页等处理
        removeToken(AMDIN_KEY)
        removeToken(AMDIN_EXPIRES_KEY)
        removeToken(AMDIN_REFRESH_EXPIRES_KEY)
        removeToken(AMDIN_REFRESH_KEY)
        router.navigate(`/login?commId=${getToken(COMMID_KEY)}`, {
          replace: true
        })
        return
      }

      const originalRequest = error.config
      if (!isRefreshing) {
        isRefreshing = true

        await fetchGetRefreshInfo()
          .then((res) => {
            // 将新的token保存到localStorage
            setUserToken(res.Data.token)

            isRefreshing = false
            const newToken = getToken(AMDIN_KEY)
            processQueue(null, newToken)
            originalRequest.headers['Authorization'] = 'Bearer ' + newToken
            return instance(originalRequest)
          })
          .catch((err) => {
            processQueue(err, null)

            return Promise.reject(err)
          })
      } else {
        return new Promise(function (resolve, reject) {
          failedQueue.push({ resolve, reject })
        })
          .then((token) => {
            originalRequest.headers['Authorization'] = 'Bearer ' + token
            return instance(originalRequest)
          })
          .catch((err) => {
            return Promise.reject(err)
          })
      }
    }
    return Promise.reject(error)
  }
)

const processQueue = (error: any, token: string | null = null) => {
  failedQueue.forEach((prom) => {
    if (error) {
      prom.reject(error)
    } else {
      prom.resolve(token)
    }
  })

  failedQueue = []
}

export default instance

export type ResType = {
  code?: number
  data?: ResDataType
  msg?: string
}

export type ResDataType = {
  [key: string]: any
}
  • service.ts

    // 刷新token
    export async function fetchGetRefreshInfo(): Promise {
    const url = ${REACT_APP_URL}/XXXXXXXXXXXXXXXXX/RefreshToken
    return axios({
    url,
    method: 'post',
    headers: {
    Authorization: Bearer ${refreshToken}
    }
    })
    }

相关推荐
一孤程38 分钟前
Airtest自动化测试第五篇:小程序与Web测试——跨平台自动化全覆盖
前端·自动化测试·小程序·自动化·测试·airtest
IT_陈寒40 分钟前
SpringBoot自动配置不是你以为的那样的智能
前端·人工智能·后端
yume_sibai2 小时前
大屏数据可视化 - 边框红绿呼吸灯实现详解
前端·信息可视化·typescript
Hyyy2 小时前
很多Desktop都在上的Computer Use是什么
前端·llm
慢功夫2 小时前
开篇:VS Code 为什么不是一个普通 React App
前端·visual studio code
你挚爱的强哥2 小时前
Vue2 实现 1.5s 十连击监听(连续点击若干次),封装通用可复用点击检测工具,不用 data!Vue 封装通用连击监听方法,支持自定义时长与点击次数
前端·javascript·vue.js
huashengzsj3 小时前
Shopify个人建站如何搭建独立站:从零开始的完整指南
前端·网络·人工智能
程序猿小泓3 小时前
从 Claude Code 学 Agent Harness:一个前端工程师的 AI Agent 学习笔记
前端·人工智能·学习
柒和远方4 小时前
从审计日志到可下载证据包:事务型 Outbox、租约 fencing 与保留水位
前端·后端·架构
minglie14 小时前
npm ali-oss库依赖冲突
前端·npm