401错误的场景
401是http的状态码,表示本次请求没有权限
表示没有登录,或没有token值
有如下两种情况会出现401错误:
- 未登陆用户做一些需要权限才能做的操作(例如:关注作者),network中会提示本次请求是401错误
- 登录用户的token过期了
理解token过期
登陆成功之后,接口会返回一个token值,这个值在后续请求时通过请求头时带上(就像是进入小区门的开门钥匙)。但是,这个值一般会有有效期(具体是多长,是由后端决定)
如果你上午8点登陆成功,到了10:01分,则token就会失效,再去发请求时,就会报401错误。
解决方法响应拦截器
axios中提供了响应拦截器功能:所有从后端回来的响应都会先进入响应拦截器,包括出错的请求中。所以,我们可以在响应拦截器中去写代码来统一解决。
让用户对因token过期产生的401错误**无感知
封装独立的history
创建文件 src\utils\history.ts
import { createBrowserHistory } from 'history'
const history = createBrowserHistory()
export default history
在app.tsx中使用
import history from '@/utils/history'
function App () {
return (
<div className="app">
<Router history={history}>
补充一个action用来去做更新token的操作,条件满足时将本地的token更新一次
export function saveToken (token: Token) : LoginAction {
// 1. 本地持久化
setToken(token)
// 2. 保存token
return {
type: 'login/token',
payload: token
}
}
下一步写响应拦截器,引入封装好的histroy,在request.ts中,添加响应拦截器
// 添加响应拦截器
instance.interceptors.response.use(
function (response) {
// 对响应数据做点什么
return response
},
async function (error:AxiosError) {
console.log(1)
//没有登录或者没有token值触发
if (error.response?.status === 401) {
Toast.show('没有权限,请先登录')
const { refresh_token } = getToken()
//没有token且没有refresh_token
if (!refresh_token) {
history.replace('/login', { from: location.pathname })
return Promise.reject(error)
}
//没有token但有refresh_token执行下面
try {
const res = await axios.put(`${baseURL}authorizations`, null, {
headers: {
Authorization: `Bearer ${refresh_token}`
}
})
store.dispatch(saveToken({ token: res.data.data.token, refresh_token }))
} catch (e) {
history.replace('/login', { from: location.pathname })
return Promise.reject(e)
}
return Promise.reject(error)
}
//没网的时候触发
if (!error.response) {
Toast.show('网络错误,请稍后再试')
return Promise.reject(error)
}
// 对响应错误做点什么
return Promise.reject(error)
}
)