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 = falselet 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 instanceexport type ResType = { code?: number data?: ResDataType msg?: string}export type ResDataType = { [key: string]: any}
- service.ts
// 刷新tokenexport async function fetchGetRefreshInfo(): Promise<ResDataType> { const url = `${REACT_APP_URL}/XXXXXXXXXXXXXXXXX/RefreshToken` return axios({ url, method: 'post', headers: { Authorization: `Bearer ${refreshToken}` } })}