一、使用axios中的疑问?
1、如果使用封装好的axios,每个请求都会执行拦截器嘛?
会的,因为axios.interceptors.request.use执行了,但是保存在函数内部的reqObj只会执行一次。
疑问???axios.interceptors.request是如何执行的????
参考promise源码自己写的axios源码实现axios文件中:只要调用Axios.prototype.request中就会执行
(1)、 Axios.prototype.request = function(config) {
let promise = Promise.resolve(config)
let chains = [dispatchRequest, undefined]
this.interceptors.request.forEach(function(interRequest) {
chains.unshift( interRequest.resolved, interRequest.rejected )
})
while( chains.length ){
promise = promise.then(chains.shift(), chains.shift())
}
return promise
}
function axiosGlobal() {
let reqObj = {}
return axios
}
Vue.prototype.$http = axiosGlobal()
this.$http.get('3000')
this.$http.get('4000')
2、axios添加全局的loading,是每个请求都会有自己的,还是统一所有的请求都使用一个?
是统一的loading,因为在 interceptors.request 中加载,reqObj为空打开loading,当自己的请求执行完将开关改为reqObj[key] = false // key = url + 时间戳
当然等所有的请求都执行完才会关闭loding,这样效果会比较好
二、axiosGlobal函数将如何封装,当然是用闭包,返回一个axios,内部的变量(reqObj)可以不被回收,因为axios.interceptors内部使用到这个变量
例如:
export function axiosGlobal() {
let reqObj = {}
axios.interceptors.request.use(config => {
if (!reqObj[key]) { // key = url + 时间戳
loading.show()
}
}
return axios
}
三、PSMU 绑定在window中的变量 尽量保持业务无关
可以在 axiosGlobal 中做封装什么
1、接口超时(特定接口不能保证请求时长的,可以排除在外)
2、封装全局 loading
3、请求头 headers 中增加所需要的key: value
3.1、请求唯一id(zing-id),方便后端查看日志
3.2、请求发送时间
3.3、是否有token,存在:增加到headers[‘Authorization’] = get.token()
4、在 响应拦截器 中统一跳转登陆页面,怎么操作的??
1、只有一个接口 code = 299,认证失败,直接跳转登陆页面,
2、为什么请求失败??
因为后端存储的 token 不能超过24小时, 首先用户先拿到后端返回的token,存起来,等超过24小时在用这个token去请求, 发现超时,登陆失败,就跳转登陆页
3、如何获取 token ?
登陆–》用户名密码———〉base64转码,请求接口,返回token,使用cookie存储
5、在 this.default.timeout 增加最大超时。
1、如何判定接口超时??
在 interceptors.request 首先记录了创建 request-time 时间, 12:00
在 interceptors.response 中响应接口时间 12:04,data.config[‘request-time’], 发现时长超过3s,给控制台打印日志
2、封装全局 loading
2.1、在 interceptors.request 中
axios.interceptors.request.use(config => {
let reqObj = {},
key = `${config.url}_${Date.now()}`
reqObj[key] = false
// 添加一个延时器,所有同步都执行完之后在显示loading
// 只要每个拦截器请求时就需要启动全局loading,每启动一个loading,后一个会clearTimeout的状态,直到最后一个启动loading
// 等每个都执行完成之后,关闭自己的url在 reqObj中的开关
// 最后每请求完成一个需要在 requestArr 删除一个url相关数据,直到为0,关闭loading
let data = {
start: new Date().getTime(),
startTime: dateFormat(new Date()),
url: config.url
}
requestArr.push(data)
let timer = setTimeout(() => {
clearTimeout(timer)
if (!reqObj[key]) {
if (isPc()) {
pc.loading.show()
} else {
app.loading.show()
}
}
}, 500)
2.2、在 interceptors.response 中
axios.interceptors.response.use(data => {
reqObj[key] = true 先将记录的某个url的开关关闭
try {
requestArr.forEach((item, index) => {
if (item.url === data.config.url) {
requestArr.splice(index, 1)
}
})
//数组为空 或者 全部都是不需要打开loading的则关闭loading
if (requestArr.length === 0) { //关闭loading
hideLoading()
}
if (forceCloseTimer) {
clearTimeout(forceCloseTimer)
}
//临时解决loading不消失的问题
forceCloseTimer = setTimeout(() => {
clearTimeout(forceCloseTimer)
hideLoading()
return
}, 1000)
} catch (error) {
hideLoading()
}
})
4、根据code返回登陆页面
4.1、(code === 297 || code === 299) 认证失败
if (!PSMU.isEmt(data.data['code']) && (data.data.code === 297 || data.data.code === 299)) {
let whiteList = ['login']
if (whiteList.indexOf(currentpath) === -1) {
PSMU.router.push('/login')
}
如果没有其他异常操作,
return data 提前结束路由response拦截\
}
4.2 第二天打开前一天的页面,会跳转让重新登陆
是因为前端存储的cookie中的token为24小时, 第二天会获取不到,后端发现没有token,会提示认证失败,跳转登陆页面
// 是否有token,存在:增加到headers['Authorization'] = get.token()
if (PSMU.isValidToken()) {
config.headers[PSMU.tokenName] = PSMU.getToken()
}
4.3 如何获取token, 用户点击登陆,会获取到token,向下传递,如果没有责登陆失败
.post('/xxxx/auth/user/loginUrl', {msg: postMsg})
.then(res => {
if (res.data.token) {
PSMU.setToken(res.data.token)
resolve()
} else {
reject(new Error('登录失败'))
}
})
.catch(err => {
reject(new Error('登录失败'))
})
5、怎么使用呢,因为在当天开发完成,不关电脑,重新请求接口,
cookie/session/localStorage 区别??请看下一篇文章