好记性不如烂笔头,记录下来,省的每次写都要回忆下。
老手参考这个,
新手参考这个。
说下核心思路,主要两点:
第一
先跟后端确认,token失效是http状态码报非200还是报200,私有属性设置。
非200,拦截响应,要在response.use error里拦截,
200要在response.use response里拦截。
axios.interceptors.response.use(
response => {
//200这里拦截
return response
},
error => {
//非200这里拦截
return error.response
}
)
第二
要有数据流,状态流的概念,只简单包层promise,加个resolve,reject是不行的。
token失效,拦截更新token后,要返回一个带着config 重新调用axios的闭包函数,
而不是执行axios请求函数.
因为重新调用axios请求,就是另外一个promise,会导致业务代码拿不到返回值
需求
假设token失效,
接口返回状态码401,
token和refreshToken都存在localstorage,
axios又被promise封装了一层
解决代码(看注释 刷新token那一段即可)
import Vue from 'vue'
import axios from 'axios'
import vueAxios from 'vue-axios'
import {
updateToken
} from '@/axios/api/login'
import {
message
} from 'ant-design-vue'
Vue.use(vueAxios, axios)
/*
* 这里写一个读取本地配置文件的方法,原生ajax,同步读取文件
*/
const getConfigration = function () {
let ajax = null
// 判断ajax对浏览器支持情况
if (window.XMLHttpRequest) {
ajax = new XMLHttpRequest()
} else if (window.ActiveXObject) {
ajax = new window.ActiveXObject()
} else {
alert('您的浏览器不支持ajax')
}
if (ajax != null) {
ajax.open('GET', '/config.json?t=' + Date.now(), false)
ajax.send(null)
ajax.onreadystatechange = function () {}
return JSON.parse(ajax.responseText)
}
}
export const configFile = getConfigration()
/**
* [http request 拦截器]
* @return
*/
axios.interceptors.request.use(
config => {
if (config.headers) {
config.headers.Authorization = localStorage.token
} else {
config.headers = {
Authorization: localStorage.token
}
}
// 用户权限
if (config.params) {
// config.params.token = '0000'
} else {
config.params = {
// token: '0000'
}
}
// 判断网络是否连接
if (window.navigator.onLine) {
return config
} else {
message.warning({
content: '请检查网络或重新登录系统!',
duration: 3
})
}
},
error => {
// 对请求错误的操作
message.error({
content: '后台服务异常!',
duration: 3
})
return Promise.reject(error)
}
)
let isRefreshing = false
let requests = []
let save = ''
axios.interceptors.response.use(
response => {
save = response
return response
},
error => {
//刷新token
if (error && error.response&&error.response.status == 401) {
const config = error.config
if (localStorage.getItem('refreshToken')) {
if (!isRefreshing) {
isRefreshing = true
return updateToken({
refreshToken: localStorage.getItem('refreshToken')
}).then(res => {
if (res.returnCode === 200) {
localStorage.setItem('token', res.data)
config.baseURL = ''
config.headers['Authorization'] = localStorage.getItem('token')
requests.forEach((item) => {
item()
})
requests = []
return axios(config)
}
}).finally(() => {
isRefreshing = false
})
}else {
return new Promise((resolve) => {
requests.push(() => {
config.baseURL = ''
config.headers['Authorization'] = localStorage.getItem('token')
resolve(axios(config))
})
})
}
} else {
Vue.prototype.$bus.$emit('gologin')
}
}
return error.response
}
)
// 处理http 请求响应码
function successState (response) {
switch (response && response.status) {
case 400:
if (response.data.returnCode === 400) {
message.warning({
content: response.data.message || '接口传参异常',
duration: 3
})
}
if (response.data.returnCode === 400009) {
// 用户未注册
break
}
if (response.data.returnCode === 400001) {
// 验证码错误
break
}
if (response.data.returnCode === 400005) {
// 账号锁定
break
}
if (response.data.returnCode === 400006) {
// 账号密码错误
break
}
if (response.data.returnCode === 400002) {
localStorage.setItem('userinfo', '')
localStorage.setItem('token', '')
localStorage.setItem('refreshToken', '')
Vue.prototype.$bus.$emit('gologin')
break
}
// message.warning({
// content: response.data.message || '接口错误',
// duration: 3
// })
break
case 401:
if (localStorage.refreshToken) {
// 刷新token
Vue.prototype.$bus.$emit('uptoken')
} else {
Vue.prototype.$bus.$emit('gologin')
}
break
case 403:
message.warning({
content: response.data.message || '未授权,权限不够',
duration: 3
})
break
case 500:
message.warning({
content: '内部服务错误',
duration: 3
})
break
case undefined:
console.log(response.data.message)
// message.error({
// content: response.data.message || '接口请求失败!',
// duration: 3
// })
break
default:
return response && response.data
}
}
function errorState (err) {
message.error({
content: '请求错误!',
duration: 3
})
}
const httpServer = (opts, data) => {
let baseUrl = '' // 这里是一个默认的url,可以没有
switch (process.env.NODE_ENV) {
case 'development':
baseUrl = configFile.devUrl
break
case 'huawei':
baseUrl = configFile.huaweiUrl
break
case 'production':
baseUrl = configFile.prodUrl
break
}
// http默认配置
let httpDefaultOpts = {
method: opts.method, // 必填
baseURL: baseUrl,
url: opts.url, // 必填
timeout: 10 * 1000,
params: data,
headers: opts.headers
}
let promise = new Promise((resolve, reject) => {
axios(httpDefaultOpts)
.then(res => {
successState(res)
// 添加响应头
res.data.headers = save
resolve(res && res.data)
})
.catch(err => {
errorState(err)
reject(err)
})
})
return promise
}
export default httpServer
网友评论