import { Message } from 'element-ui'
import axios from 'axios'
import router from '@/router/index'
import { base } from './baseUrl'
/**
* 请求失败后的错误统一处理
* @param {Number} status 请求失败的状态码
* @param {String} message请求失败的返回信息
*/
const errorHandle = (status, message) => {
// 状态码判断
switch (status) {
case 401:
getRefreshToken()
break
case 403:
Message.error(message)
router.push('403')
// 无权限,提示无权限信息
// 403 token失效,请求刷新token,刷新token也失效,再跳转登录页
break
// 404请求不存在
case 404:
router.push('404')
break
case 500:
Message.error(message)
break
default:
Message.error(message)
}
}
// 刷新token
function getRefreshToken() {
let refreshToken = localStorage.getItem('refreshToken')
let url = `${base.dev}/refreshtoken/Get?refresh_token=${refreshToken}`
return axios
.get(url)
.then(res => {
return Promise.resolve(res.data)
})
.catch(err => {
return Promise.reject(err)
})
}
//判断token是否到期--提取30秒到期
const isTokenExp = () => {
let expTime = parseInt(localStorage.getItem('expTime')) //本地token存储的时间
// 当前秒的时间戳,不含毫秒数
let currentTime = parseInt(new Date().getTime() / 1000 + 30)
return currentTime >= expTime ? true : false
}
// 请求刷新token的开关
window.isRefreshing = false
// 拦截所有发送请求的数组
let currentAjaxArr = []
// 数组中的请求得到新的token之后自执行,用新的token去请求数据
function onRefreshed(token) {
// console.log('重新发送积攒的请求')
currentAjaxArr.map(cb => cb(token))
}
// 将所有的请求都push到数组中
function subscribeTokenRefresh(cb) {
// console.log('添加请求')
currentAjaxArr.push(cb)
}
// 创建axios实例,超时时间为10秒
let instance = axios.create({
timeout: 1000 * 10
})
/**
* 请求拦截器
* 每次请求前,如果存在token则在请求头中携带token
*/
instance.interceptors.request.use(
// 登录流程控制中,根据本地是否存在token判断用户的登录情况
// 但是即使token存在,也有可能token是过期的,所以在每次的请求头中携带token
// 后台根据携带的token判断用户的登录情况,并返回给我们对应的状态码
// 而后我们可以在响应拦截器中,根据状态码进行一些统一的操作。
config => {
const token = localStorage.getItem('accessToken')
if (token) {
// debugger
config.headers.token = token
if (config.url.indexOf('file/UploadFile') === -1) {
config.headers['Content-Type'] = 'application/json'
} else {
config.headers['Content-Type'] = 'multipart/form-data'
}
// 判断是否token过期
// console.log('开始拦截')
if (isTokenExp() && config.url.indexOf('/refreshtoken/') === -1) {
// console.log('token过期了,开始刷新token')
// 是否正在刷新token,不是的话讲之后的token全部push到数组中
if (!window.isRefreshing) {
// console.log('正在刷新token')
window.isRefreshing = true
getRefreshToken()
.then(res => {
window.isRefreshing = false
if (res.Success) {
// console.log('刷新token成功')
localStorage.setItem('accessToken', res.Data.access_token)
localStorage.setItem('expTime', res.Data.exp)
localStorage.setItem('refreshToken', res.Data.refresh_token)
// console.log('token已经更新')
config.headers.token = res.Data.access_token
onRefreshed(res.Data.access_token)
currentAjaxArr = []
} else {
// console.log('刷新token失败')
Message.error(res.Message)
sessionStorage.clear()
localStorage.clear()
router.push('login')
currentAjaxArr = []
}
})
.catch(err => {
Message.error(err)
sessionStorage.clear()
localStorage.clear()
router.push('login')
// console.log(err)
})
let retry = new Promise((resolve, reject) => {
subscribeTokenRefresh(token => {
config.headers.token = token
resolve(config)
})
})
// console.log('过期判断结束')
return retry
} else {
let retry = new Promise((resolve, reject) => {
subscribeTokenRefresh(token => {
config.headers.token = token
resolve(config)
})
})
// console.log('正在刷新,拦截其他多余请求')
return retry
}
// console.log('token过期了,结束刷新token')
// return config
} else {
return config
}
} else {
sessionStorage.clear()
localStorage.clear()
router.push('login')
return config
}
},
error => Promise.error(error)
)
// 响应拦截器
instance.interceptors.response.use(
// 请求成功
res => {
if (res.status === 200) {
if (!res.data.Success) {
Message.error(res.data.Message)
}
return Promise.resolve(res.data)
}
// return res.status === 200 ? Promise.resolve(res.data) : Promise.reject(res)
},
// 请求失败
error => {
const { response } = error
if (response) {
// 请求已发出,但是不在2xx的范围
errorHandle(response.status, response.data.Message)
//403返回的值在response.data.Message
return Promise.reject(response)
} else {
// 处理断网的情况
// eg:请求超时或断网时,更新state的network状态
// 关于断网组件中的刷新重新获取数据,会在断网组件中说明
if (!window.navigator.onLine) {
// store.commit("changeNetwork", false)
} else {
return Promise.reject(response)
}
}
}
)
token过期后,使用refresh_token刷新token,并且续约之前已发送的请求
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 本文参考:https://www.jianshu.com/p/7a2d2d7497a1(主要参考)https://...
- RxJava2 实战系列文章 RxJava2 实战知识梳理(1) - 后台执行耗时操作,实时通知 UI 更新RxJ...
- 环境 vue项目,axios, JwtToken 问题 前端页面长时间登录未操作后, 发送请求无反应,发送任何请求...
- 此博客是参考http://blog.csdn.net/jdsjlzx/article/details/524421...
- 1.在开发过程中,我们都会接触到token,token的作用是什么呢?主要的作用就是为了安全,用户登陆时,服务器会...