关于401错误
为什么要提到401,因为响应拦截器可以处理401错误
401错误场景
1. 用户未登录,代码报401,应该回到登录页
2. 登录用户的token过期 :
怎样理解token过期?
. 就是登录成功了以后,后端会返回一个token值,这个值在后续请求时带上(就像是开门钥匙),<br /> 但是,这个值一般会有**有效期**(具体是多长,是由后端决定)token过期是为了安全起见
refresh_token
说明 : 当用户登陆成功之后,返回的token中有两个值
图示说明:
作用:
响应拦截器
注意:
1. 响应拦截器可以解决401错误
2. 但是并不是所有的响应拦截器都是处理401的(只是为了提升用户体验的),像公司内部的那种
后台管理器就不需要
响应拦截器的功能
这里仅仅仅仅只列举了两条
1. 所有从后端回来的响应都会集中进入响应拦截器中,如果发生401错误就可以解决
2.解决登录失败不报错的问题
3.还可以对axios接口返回值做一个脱壳处理
什么是脱壳处理? 就是我们发现axios在处理接口返回值时,默认会自动给包裹一个data
字段,这导致我们每次在业务模块获取数据都需要写res.data.data.xxx,就特别麻烦
1.解决401错误
图示说明
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21762447/1623774823120-22c18851-f1b2-463e-b547-04108ac75cca.png#clientId=u0721dea6-1fa3-4&from=paste&height=186&id=uc40cc699&margin=%5Bobject%20Object%5D&name=image.png&originHeight=186&originWidth=555&originalType=binary&ratio=1&size=45692&status=done&style=none&taskId=u2c24806a-2e46-46a4-817b-8c5d5320eab&width=555)
代码演示
import router from '../router/auth.js'
// 响应拦截器
request.interceptors.response.use(function (response) {
console.log('响应拦截器', response)
return response
}, async function (error) {
// 如果发生了错误,判断是否是401
console.dir(error)
if (error.response.status === 401) {
// 出现401就在这里面 开始处理 ---
console.log('响应拦截器-错误-401')
const refreshToken = store.state.tokenInfo.refresh_token
// if (有refresh_token) { ---- 有refresh_token
if (refreshToken) {
// 1. 请求新token
try {
const res = await axios({
url: 'http://localhost:8000/v1_0/authorizations',
method: 'PUT',
headers: {
Authorization: `Bearer ${refreshToken}`
}
})
console.log('请求新token', res.data.data.token)
// 2. 保存到vuex
store.commit('mSetToken', { // mSetToken是前面定义的mutations名字
refresh_token: refreshToken,
token: res.data.data.token
})
// 3. 重发请求
// request是上面创建的axios的实例,它会自动从vuex取出token带上
return request(error.config)
} catch (error) {
// 1. 清除token
store.commit('mSetToken', {})
// 2. 去到登录页(如果有token值,就不能到login)
const backtoUrl = encodeURIComponent(router.currentRoute.fullPath)
router.push('/login?backto=' + backtoUrl)
return Promise.reject(error)
}
} else {
// 如果没有refresh_token的时候 ----没有refresh_token
// 1.去到登录页
// 2.清除token
store.commit('mSetToken', {})
const backtoUrl = encodeURIComponent(router.currentRoute.fullPath) // 回到原来跳过来的的页面,不加?后面的一串就会到首页
router.push('/login?backto=' + backtoUrl)
return Promise.reject(error) // 返回错误信息
}
} else {
return Promise.reject(error)
}
})
原理
它的执行顺序是: 请求接口 —> 发生401报错 —> 判断是否有refresh_token —>如果有就用fresh_token请求新的token —> 后台成功返回一个新的token给我们 —> 更新vuex —> 然后重新发送请求 —> 带上新的token请求数据
如果是异常情况: 就是没有fresh_token的情况
2.解决登录失败不报错的问题,对axios接口返回值做一个脱壳处理
注意: 这个例子中的success根据实际后端返回的数据而定,每个接口不一样,这里仅做例子
// 响应拦截器中
// 1. 根据后端返回的数据判断本次操作是否成功,不成功 主动报错
// 2.如果成功,只返回有效数据
service.interceptors.response.use(
response => {
if (response.data.success) {
return response.data // 1. 把返回数据外面包裹的data去掉了 就不用每次写res.data.data这些这样麻烦了
} else {
// 如果success为false 业务出错,直接触发reject
// 2. 被catch分支捕获 (是login.vue的doLogin发请求里面的try,catch)
return Promise.reject(new Error(response.data.message))
}
},
error => {
console.log(error)
return Promise.reject(error)
}
)