无痛/无感刷新token的思路:
背景:
- token有效期只有2小时,保证数据的安全
- token失效了之后,不能直接拦截到登录页(用户体验不好)
目标:
思路:
- 配置axios的响应拦截器
- 通过响应拦截器捕获401异常
- 判断
error.response.status
是否是401
- 如果不是401,说明不是由于token过期导致,不用管。
- 如果错误码是401,说明token过期了。判断vuex中是否有refresh_token刷新token
- 如果没有,直接拦截到登录页面(删除vuex中token,跳转到登录页,提示)
- 如果有refresh_token, 拿着刷新token重新新的token。
- 如果成功了,获取到新的token,并且更新到vuex中。重新发送一个请求(才能保证用户无感)
- 如果失败了,直接拦截到登录页面(删除vuex中token,跳转到登录页,提示)
import axios from 'axios'
// 因为不是在组件中,所以要导入store router 另外导入了vant-ui的Toast组件
import store from '@/store'
import router from '@/router'
import { Toast } from 'vant'
// 添加响应拦截器
request.interceptors.response.use(function (response) {
return response.data
}, async function (error) {
// console.dir(error)
// 判断状态码
if (error.response.status === 401) {
// 拿到刷新token
const refreshtoken = store.state.user.token.refresh_token
// 判断 没有刷新token的处理代码
if (!refreshtoken) {
// 清除过期token
store.commit('user/removeToken')
// 跳转到login
router.push({
path: '/login',
query: {
back: router.currentRoute.path
}
})
Toast.fail('登录过期')
return
}
// 有刷新token
// 要try catch 因为刷新token一般14天过期 有可能还会获取不到refresh_token
try {
const res = await axios({
method: 'PUT',
url: baseURL + 'v1_0/authorizations',
headers: {
Authorization: 'Bearer ' + refreshtoken
}
})
// console.log(res) // res.data.data.token
store.commit('user/setToken', {
token: res.data.data.token,
refresh_token: refreshtoken
})
// 重新发送请求
return request(error.config)
} catch {
store.commit('user/removeToken')
router.push({ path: '/login', query: { back: router.currentRoute.path } })
Toast.fail('登录失效')
}
} else {
return Promise.reject(error)
}
})
其中要注意的是:
- console.dir(error) 能够获取到错误信息。比如:response中的status、和config中的请求信息等等
- 因为不是在组件中,无法直接使用$route.path,可以通过router.currentRoute,等于是当前路由对应的路由信息对象。