401错误的场景
-
未登陆用户做一些需要权限才能做的操作(例如:关注作者),代码会报出401错误。这种情况下,应该让用户回到登陆页。
-
登录用户的token过期了
整体目标是:通过axios响应拦截器来处理401问题。
refresh_token和token的作用
-
token:
-
作用:在访问一些接口时,需要传入token,就是它。
-
有效期:2小时(安全)。
-
-
refresh_token
-
作用: 当token的有效期过了之后,可以使用它去请求一个特殊接口(这个接口也是后端指定的,明确需要传入refresh_token),并返回一个新的token回来(有效期还是2小时),以替换过期的那个token。
-
有效期:14天。(最理想的情况下,一次登陆可以持续14天。)
-
401问题-思路-响应拦截器
axios中提供了响应拦截器功能:所有从后端回来的响应都会集中进入响应拦截器中。所以,我们可以在响应拦截器中去写代码来统一解决。
由于这里涉及到非组件内路由跳转,所以需要提前封装独立的history 这里可以看我React 在非组件环境拿到路由信息_捧鲜花的唐老鸭的博客-CSDN博客https://blog.csdn.net/weixin_58207509/article/details/121413518?spm=1001.2014.3001.5502
这一篇博客
核心代码 里面包含(typescript)
/* eslint-disable camelcase */
// axios 封装
// 1. 基地址
// 2. 请求拦截器
// 3. 响应拦截器
// 封装axios
import { Toast } from 'antd-mobile'
import axios, { AxiosError } from 'axios'
import { getToken, hasToken, removeToken, setToken } from './storage'
import history from './history'
import store from '@/store'
import { saveToken } from '@/store/actions/login'
// import store from '@/store'
const baseURL = 'http://geek.itheima.net/v1_0/'
const instance = axios.create({
baseURL,
timeout: 5000
})
// 添加请求拦截器
instance.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
if (hasToken()) {
const token = getToken().token
// 添加到请求头
config.headers!.Authorization = `Bearer ${token}`
}
return config
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error)
}
)
// 添加响应拦截器
instance.interceptors.response.use(
function (response) {
// 对响应数据做点什么
return response
},
async function (error: AxiosError) {
if (!error.response) {
Toast.show('网络异常')
return Promise.reject(error)
}
if (error.response.status !== 401) {
Toast.show('操作异常')
return Promise.reject(error)
}
if (error.response.status === 401) {
// 1 获取refresh_token
const { refresh_token } = getToken()
// 2 发请求重新获取token
try {
const res = await axios.put(baseURL + 'authorizations', null, { headers: { Authorization: `Bearer ${refresh_token}` } })
// 3 本地 存储token
setToken({ token: res.data.data.token, refresh_token })
// 4 redux存储token
store.dispatch(saveToken({ token: res.data.data.token, refresh_token }))
// 5 重新之前报错的发请求
return instance(error.config)
} catch (err) {
// 2.2 如果 refresh_token 也过期了 回到登录页 重新登录
history.push('/login')
// 2.3 清空token
removeToken()
return Promise.reject(err)
}
}
console.log(history)
// 对响应错误做点什么
return Promise.reject(error)
}
)
export default instance