项目当中列表查看目标云主机的监控,页面当中以定时器内每一秒发出一次请求方式来实现实时刷新数据,当点击列表选项卡后,监控页面刷新数据的axios请求有pending状态,此时在列表页(即父页面)会弹出监控页面(即子页面)的弹框,实现目标:即在监控页面切换到列表页面时,关闭监控页面的定时器和pending状态请求。

会遇到的问题:

  1. 当打开监控页面接口正常的时候,定时器正常运行,点击切换列表页后pending的请求完成,在列表页会继续执行后续逻辑,找不到对应的就会报错,即走到服务器错误弹出框,因此会在此时弹出n个框。*************解决办法:在页面销毁的时候将定时器关闭,在axios请求头加上官网文档介绍的关闭pending请求的东西,并在销毁实例的生命周期函数当中将其关闭,并将axios.catch(){}中的代码加上try{}catch(res){}
  2. 我在axios报错的时候捕获异常,弹框后跳转列表页当中,此时因为前几个pending的请求可能会导致定时器比第一个请求报错需要执行的逻辑代码要快,即在顶一个请求还未做出反应的时候,定时器可能已经执行多个axios请求,所以依然会在切换到列表页弹出多个框。***************解决办法:axios请求报错之后就需要进行定时器关闭、取消pending请求和重置定时器。然后在data中定义一个执行标记,在弹框之前进行判断此标记并在判断内第一行执行标记取反,后续再执行弹框

这样的结局办法页面当中可以解决,页面上虽然看不出来,但是可以请求还是会多出几个来,数据量非常庞大的情况下也不建议使用定时器这样的方式来进行实时数据刷新(我这块的数据量没有非常多),数据量大想要实现页面数据实时刷新,建议使用websocket和后台进行长连接,在实例销毁时关闭长连接即可,也不会出现这篇博文的情况。

data数据定义

data (){
	return {
		intervalTimer:null,//定时器
        axiosFlag:true//catch中的弹框标记
	}
}

方法、生命周期函数

destroyed (){
    clearInterval(this.intervalTimer)//关闭定时器
    this.intervalTimer=null  //重置定时器
},
mounted (){
	this.initTable();
},
methods:{
	initTable(){
		var _this=this
        let CancelToken = _this.$axios.CancelToken
        _this.axiosFlag=true//刷新页面将此标记重置
         _this.intervalTimer=setInterval(function(){//定时调用接口
            _this.$axios.get(`/api/monitor/detail/${_this.serviceStatus.id}`, {
                cancelToken: new CancelToken(function executor(c) {//axios自带关闭请求方法
                    _this.cancel = c
                    // console.log(c)
                    // 这个参数 c 就是CancelToken构造函数里面自带的取消请求的函数,这里把该函数当参数用
                })
            }).then(res => {
                if(res.status === 200){
                    //处理页面加载需要的数据
                    _this.info=res.data
                    _this.loadDiskUsage()
                    _this.loadMemoryUsage()
                }
            }).catch(res => {
                try{//捕获异常(在接口请求不报错的情况下,点击列表页还会出现弹框,因为pending完成之后请求找不到对应的字段,这时候只需要try catch 捕获异常即可)
                    _this.cancel()//取消pending中的请求
                    clearInterval(_this.intervalTimer) //关闭定时器
                    _this.intervalTimer=null //重置定时器
                    if(res.response.status === 500 || res.response.status === 404 || res.response.status === 504){
                        if(_this.axiosFlag){//报错后是否弹窗标记,
                            _this.axiosFlag=false
                            _this.$message({
                                message: '系统错误,请重新查看!',
                                type: 'error',
                                onClose:res =>{
                                    _this.$router.push('serviceStatus')
                                }
                            });
                        }
                    }
                }catch(res){
                    // console.log(res)
                }
                
            })                    
        },1000)
	}
}

2020/5/6 vuex存储请求路由跳转利用cancelToken来关闭上一个页面的请求

main.js

// 添加请求拦截器,在请求头中加token
axios.interceptors.request.use(config => {
  config.cancelToken = new axios.CancelToken(function (cancel) {
    store.commit('pushToken', {cancelToken: cancel})
  })
  return config;
}, error => {
// 对请求错误做些什么
  return Promise.reject(error);
});

state.js

let cancelTokenArr=[]
export default {
    cancelTokenArr
}

mutations.js

export default{
	pushToken (state, payload) {
        state.cancelTokenArr.push(payload.cancelToken)
    },
    clearToken (state) {
        state.cancelTokenArr.forEach(item => {
            item('路由跳转取消上一页的请求')
        })
        state.cancelTokenArr = []
    }
 }

router.js(next() 之前进行 清空store中的pending请求数组 达到关闭正在pending的请求 抛出异常)

// 配置路由权限
router.beforeEach((to, from, next) => {
    let getTokenPath=to.path
    // console.log(to.path)
    if(getTokenPath === '/single_sign_on'){//判断是否是固定的权限访问授权路由
        let token = to.query.token
        let appid = to.query.appid
        if(token){
            // 通过 token 访问第三方api 获取有效key进入首页并将key存入localstorage 否则进入login
            axios.get('/inapi/login/index',{
                headers:{
                    token:token,
                    appid:appid
                }}).then(res => {
                    if(res.data.code === 0){
                        store.commit('set_xaiot_token_key',res.data.data.role)
                        store.commit('set_xaiot_token',token)
                        store.commit('set_username',res.data.data.role)
                        store.commit('clearToken')
                        next('/')
                    }else{
                        localStorage.clear()
                        sessionStorage.clear()
                        store.commit('clearToken')
                        next('/login')
                    }
            }).catch(res => {
                // console.log(res.data.msg,'error')
                localStorage.clear()
                sessionStorage.clear()
                store.commit('clearToken')
                next('/login')
            })
        }else{
            localStorage.clear()
            sessionStorage.clear()
            store.commit('clearToken')
            next('/login')
        }
    }
    let xaiot_token=store.state.xaiot_token
    if (to.meta.requireAuth) { // 判断该路由是否需要登录权限
        if (xaiot_token) { // 判断本地是否存在access_token
          store.commit('clearToken')
            next()
        } else {
            // 未登录,跳转到登陆页面,并且带上 将要去的地址,方便登陆后跳转。
            localStorage.clear()
            sessionStorage.clear()
            store.commit('clearToken')
            next('/login')
        }
    } else {
      store.commit('clearToken')
        next()
    }
  })
export default router
Logo

前往低代码交流专区

更多推荐