好烦啊!怎么又401了!

712 阅读2分钟

401错误的场景

401是http的状态码,表示本次请求没有权限

表示没有登录,或没有token值

有如下两种情况会出现401错误:

  1. 未登陆用户做一些需要权限才能做的操作(例如:关注作者),network中会提示本次请求是401错误
  2. 登录用户的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)
  }
)