实际测试的时候如果有多个并发请求,因为登录被挤掉了,所以被后端拦截器直接处理返回了-9991状态码,响应时间相差无几,会出现多次弹出去登录的确认框。所以源码里我也加入了防止重复多次弹出提示的限制。
import Axios from 'axios'
import Config from '../config/config-1'
import { Notification, Loading, MessageBox } from 'element-ui'
let isShowConfirm = false
const service = Axios.create({
baseURL: Config.apiUrl + '/' + Config.apiPrefix,
headers: {
'Content-Type': 'application/json; charset=UTF-8'
},
withCredentials: true,
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // 默认的
timeout: Config.timeout
})
service.defaults.retry = Config.requestRetry // 重试次数
service.defaults.retryDelay = Config.requestRetryDelay // 重试延时
const CancelToken = Axios.CancelToken
var cancel
service.interceptors.request.use(
config => {
if (!config.closeLoading) {
window.loadingInstance = Loading.service({
lock: true,
text: '加载中……',
spinner: 'el-icon-loading',
background: 'rgba(255, 255, 255, .01)'
// target: document.querySelector('.loading-area')
})
// 创建一个计数器,主要是解决速度太快,并发请求导致遮罩(单例)提前关闭问题
if (!window.count) {
window.count = 1
} else {
window.count++
}
console.log(window.count)
}
let token = sessionStorage.getItem('token')
if (token) {
config.headers.common['Authorization'] = token
}
config.cancelToken = new CancelToken(function executor (c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c
})
return config
},
error => {
Promise.reject(error)
}
)
service.interceptors.response.use(
response => { // Grade
if (!response.config.closeLoading) {
setTimeout(_ => {
// 计数器,主要是解决速度太快,并发请求导致遮罩(单例)提前关闭问题
if (window.count) {
window.count--
if (window.count === 0) {
window.loadingInstance.close()
}
console.log(window.count)
}
}, 400)
}
const res = response
if (res.status !== 200) {
Notification({
title: '数据返回出错',
message: '请稍后重试',
type: 'warning'
})
// return Promise.reject('error')
} else {
if ((res.config).hasOwnProperty('closeInterceptors') && res.config.closeInterceptors) {
return res.data
}
// 根据服务器返回的token进行更新操作
if (res.headers.expired) {
sessionStorage.setItem('token', res.headers.token)
sessionStorage.setItem('expired', res.headers.expired)
}
// 下载操作
if (res.headers['content-type'] === 'application/octet-stream') {
return res.data
}
// console.log(res.data)
if (res.data.code !== 10000) {
if (res.data.code !== -9991) {
Notification({
title: res.data.message,
type: 'warning'
})
}
// 对响应数据做点什么,登录的时候保存["无登录",-9994],["登录时间过期",-9993]
if (res.data.code === -9994 || res.data.code === -9993) {
sessionStorage.setItem('token', null)
sessionStorage.setItem('expired', null)
}
if (res.data.code === -9991) {
cancel()
if (isShowConfirm) return
isShowConfirm = true
MessageBox.confirm(res.data.message + '点击确定跳转到登陆页', '提示', {
showClose: false,
confirmButtonText: '确定',
showCancelButton: false,
closeOnClickModal: false,
closeOnPressEscape: false,
type: 'warning'
}).then(res => {
toLogin()
})
}
if (res.data.code === -9994 || res.data.code === -9993) {
toLogin()
}
// 自定义异常
let ex = new Error()
ex.status = res.status
ex.code = res.data.code
return Promise.reject(ex)
}
return res.data
}
},
error => {
setTimeout(_ => {
window.loadingInstance.close()
window.count = 0
}, 400)
if (!isShowConfirm) {
// 如果弹出了其它地方登录,则不再提示请求错误
Notification({
title: '请求未响应',
message: '服务器可能出了点问题',
type: 'warning'
})
}
// console.log(error)
return Promise.reject(error)// 千万不能去掉,,,否则请求超时会进入到then方法,导致逻辑错误。
}
)
function toLogin () {
sessionStorage.removeItem('expired')
sessionStorage.removeItem('token')
sessionStorage.removeItem('permission')
sessionStorage.removeItem('buttonPermission')
window.location.href = '/login'
}
export default service