Vue中使用axios的响应拦截器处理请求失败的情况(处理token过期问题)以及 登录成功跳转回原来页面问题
Posted 小小白学计算机
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue中使用axios的响应拦截器处理请求失败的情况(处理token过期问题)以及 登录成功跳转回原来页面问题相关的知识,希望对你有一定的参考价值。
// 响应拦截器
// Add a response interceptor
request.interceptors.response.use(
// 在2xx范围内的任何状态代码都会触发此函数,这里主要用于处理响应数据
response => {
return response
},
// 任何超出2xx范围的状态码都会触发此函数,这里主要用于处理响应错误
error => {
const { status } = error.response
if (status === 401) { // 未授权
} else if (status === 403) { // 没有权限
} else if (status === 404) { // 资源不存在
Toast.fail({
message: '请求资源不存在',
forbidClick: true
})
} else if (status >= 500) { // 服务端异常
Toast.fail({
message: '服务端异常,请稍后重试',
forbidClick: true
})
}
// 将未处理的异常往外抛
return Promise.reject(error)
})
处理 token 过期
token过期后,如果发现存在user和token则发送 刷新token的请求,请求头中携带上refresh_token的值,
请求成功后,把获取到的最新的token设置给vuex容器中的user。
因为每次请求时,请求拦截器会从vuex容器中拿token。
这样即使用户token过期了,也会自动去发送刷新token的请求来获取最新的token,而不需要用户手动去登录!
/*
* 请求模块
* */
import axios from 'axios'
// 在非组件模块中获取store 必须采用这种方式
import store from '../store/index.js'
import JSONbig from 'json-bigint'
import { Toast } from 'vant'
import router from '../router'
const request = axios.create({
baseURL: '/api', // 基础路径
transformResponse: [function (data) {
// Do whatever you want to transform the data
// console.log(data)
// 后端返回的数据可能不是 JSON 格式字符串
// 如果不是的话,那么 JSONbig.parse 调用就会报错
// 所以我们使用 try-catch 来捕获异常,处理异常的发生
try {
// 如果转换成功,则直接把结果返回
return JSONbig.parse(data)
} catch (err) {
console.log('转换失败', err)
// 如果转换失败了,则进入这里
// 我们在这里把数据原封不动的直接返回给请求使用
return data
}
// axios 默认在内部使用 JSON.parse 来转换处理原始数据
// return JSON.parse(data)
}]
})
const refreshTokenReq = axios.create({
baseURL: '/api' // 基础路径
})
// 请求拦截器
request.interceptors.request.use(function (config) {
const { user } = store.state
// 如果用户已登录,统一给接口设置token
if (user) {
config.headers.Authorization = `Bearer ${user.token}`
}
// 处理完之后一定要把config 返回,否则请求发不出去
return config
}, function (err) {
return Promise.reject(err)
})
// 响应拦截器
request.interceptors.response.use(function (response) {
// 响应成功进入这里
return response
}, async function (error) {
// 响应失败进入这里
const status = error.response.status
if (status === 400) {
// 客户端请求参数错误
Toast.fail('客户端请求参数错误')
} else if (status === 401) {
// token无效
// 如果没有 user 或者 user.token, 直接去登录
const { user } = store.state
if (!user || !user.token) {
// 直接跳转到登录页面
return redirectLogin()
}
// 使用refresh_token,则请求获取新的token
try {
const { data } = await refreshTokenReq({
method: 'PUT',
url: '/app/v1_0/authorizations',
headers: {
Authorization: `Bearer ${user.refresh_token}`
}
})
// 拿到新的token之后把它更新到容器中
user.token = data.data.token
store.commit('setUser', user)
// 把失败的请求重新发送出去
// error.config 是本次请求的相关配置项
// 注意: 这里使用request发请求,它会走自己的请求拦截器,它的请求
// 拦截器中通过store容器访问token数据
return request(error.config)
// console.log(data)
} catch (err) {
// 刷新token都失败了,直接跳转到登录页
redirectLogin()
}
} else if (status === 403) {
// 没有权限操作
Toast.fail('没有权限操作')
} else if (status >= 500) {
// 服务端异常
Toast.fail('服务端异常,请稍后重试!')
}
// console.dir(error)
return Promise.reject(error)
})
function redirectLogin () {
router.replace('/login')
}
// 导出
export default request
登录成功跳转回原来页面
首先在响应拦截器中:
注意:
router.currentRoute 和 我们在组件中获取的this.$route是一个东西
// 响应拦截器
request.interceptors.response.use(
// 响应成功进入第1个函数
// 该函数的参数是响应对象
function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response
},
// 响应失败进入第2个函数,该函数的参数是错误对象
async function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
// 如果响应码是 401 ,则请求获取新的 token
// 响应拦截器中的 error 就是那个响应的错误对象
console.dir(error)
if (error.response && error.response.status === 401) {
// 校验是否有 refresh_token
const user = store.state.user
if (!user || !user.refresh_token) {
// router.push('/login')
+ redirectLogin()
// 代码不要往后执行了
return
}
// 如果有refresh_token,则请求获取新的 token
try {
const res = await axios({
method: 'PUT',
url: 'http://ttapi.research.itcast.cn/app/v1_0/authorizations',
headers: {
Authorization: `Bearer ${user.refresh_token}`
}
})
// 如果获取成功,则把新的 token 更新到容器中
console.log('刷新 token 成功', res)
store.commit('setUser', {
token: res.data.data.token, // 最新获取的可用 token
refresh_token: user.refresh_token // 还是原来的 refresh_token
})
// 把之前失败的用户请求继续发出去
// config 是一个对象,其中包含本次失败请求相关的那些配置信息,例如 url、method 都有
// return 把 request 的请求结果继续返回给发请求的具体位置
return request(error.config)
} catch (err) {
// 如果获取失败,直接跳转 登录页
console.log('请求刷线 token 失败', err)
// router.push('/login')
+ redirectLogin()
}
}
return Promise.reject(error)
}
)
+ function redirectLogin () {
+ // router.currentRoute 当前路由对象,和你在组件中访问的 this.$route 是同一个东西
// query 参数的数据格式就是:?key=value&key=value
+ router.push('/login?redirect=' + router.currentRoute.fullPath)
+ }
然后在登录成功以后:
const redirect = this.$route.query.redirect || "/";
this.$router.push(redirect);
以上是关于Vue中使用axios的响应拦截器处理请求失败的情况(处理token过期问题)以及 登录成功跳转回原来页面问题的主要内容,如果未能解决你的问题,请参考以下文章
vue中axios请求拦截器和响应拦截器 以及401状态处理