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<ResDataType> {
    const url = ${REACT_APP_URL}/XXXXXXXXXXXXXXXXX/RefreshToken
    return axios({
    url,
    method: 'post',
    headers: {
    Authorization: Bearer ${refreshToken}
    }
    })
    }

相关推荐
专注API从业者3 分钟前
基于 Flink 的淘宝实时数据管道设计:商品详情流式处理与异构存储
大数据·前端·数据库·数据挖掘·flink
龙在天4 分钟前
H5开发,开发照相机,以及组件封装
前端
曼妥思10 分钟前
PosterKit:跨框架海报生成工具
前端·开源
binqian30 分钟前
【异步】js中异步的实现方式 async await /Promise / Generator
开发语言·前端·javascript
Jerry说前后端39 分钟前
Android 移动端 UI 设计:前端常用设计原则总结
android·前端·ui
熊猫钓鱼1 小时前
基于Trae CN与TrendsHub快速实现的热点百事通
前端·trae
LIUENG1 小时前
Vue3 响应式原理
前端·vue.js
讨厌吃蛋黄酥1 小时前
前端居中九种方式血泪史:面试官最爱问的送命题,我一次性整明白!
前端·css
龙在天1 小时前
🤩 用Babel自动埋点,原来这么简单!
前端
Hierifer1 小时前
跨端实现之网络库拦截
前端