vue axios 封装请求拦截多次弹窗的问题

1,现在在页面中调用后台API需要校验token的有效性,因此使用以下代对axios 进行封装。当token过期或者失效后,进行弹窗提示用户点击重新登录返回至登录界面。一些页面中初始加载时需要调用多个api,因此会出现多次的弹窗提示,如何让只弹窗一次后续的api不再调用。即当前页面如果调用的第一个api返回500后就不执行调用后续api的代码。

service.interceptors.response.use(
    response=>{
        const res=response.data;
        return response.data;
    },err=>{
        console.log(err);
        let errCode=err.response.data.errCode;
        let errMsg=err.response.data.errMsg;
        if(errCode===500&&errMsg=='Invalid token'){
            MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录!','确认登出',{
                confirmButtonText:'重新登录',
                cancelButtonText:'取消',
                type:'warning'
            }).then(()=>{
                store.dispatch('FedLogOut').then(()=>{
                    router.push('/login');
                    Message({
                        //message:err.response.data.errMsg,
                        message:'登录信息已失效',
                        type:'error',
                        duration:5*1000
                    })
                })
            })
            
        }
        else if(errCode===500&&errMsg=='No authority'){
            router.push('/');
            Message({
                //message:err.response.data.errMsg,
                message:'无操作权限!',
                type:'error',
                duration:5*1000
            })
        }
    }
)
阅读 13.3k
4 个回答

借用楼上说的 cancel token 贴下具体实现的代码

+ const CancelToken = axios.CancelToken;
+ const pending = [];

service.interceptors.response.use(
    response=>{
        const res=response.data;
        return response.data;
    },err=>{
        console.log(err);
        let errCode=err.response.data.errCode;
        let errMsg=err.response.data.errMsg;
        if(errCode===500&&errMsg=='Invalid token'){
+        // 登录超时,接口请求多次,导致弹框会多次出现,方案:只弹一次
+        while (pending.length > 0) {
+          pending.pop()('请求中断');
+         }
            ...
            
        }
        else if(errCode===500&&errMsg=='No authority'){
        // 登录超时,接口请求多次,导致弹框会多次出现,方案:只弹一次
+        while (pending.length > 0) {
+          pending.pop()('请求中断');
+         }
            ...
        }
    }
)

+ // axios 相关配置修改
+ const defaultConfig = {}

+ defaultConfig.cancelToken = new CancelToken(function executor(c) {
+    // An executor function receives a cancel function as a parameter
+    pending.push(c);
+  });

axios(defaultConfig);

====================================
附上比较笨的方法,设置一个变量计数

let count = 0;

service.interceptors.response.use(
    response=>{
        const res=response.data;
        return response.data;
    },err=>{
        console.log(err);
        let errCode=err.response.data.errCode;
        let errMsg=err.response.data.errMsg;
        if(errCode===500&&errMsg=='Invalid token'){
+        // 登录超时,接口请求多次,导致弹框会多次出现,方案:只弹一次
+        if (count === 0) {
+          
+         }
            ...
            
        }
        else if(errCode===500&&errMsg=='No authority'){
        // 登录超时,接口请求多次,导致弹框会多次出现,方案:只弹一次
+        if (count === 0) {
+          
+         }
            ...
        }
        count++;
    }
)

axios是可以使用 cancel token 取消请求的。

我的做法一般是,先请求一个判断用户登录的接口, 再请求其它接口.

如果按你现有逻辑,需要把无需权限的请求与需要权限的请求分成开, 再做个标记.

//1. 创建一个axios 专供需要权限的接口用.
const axiosToken = axios.create();

//2. 通过标记判断是否需要弹对话框
var then = (function(){
    var unLoginIsShow = false;
    function ok(res){
        unLoginIsShow = false;
        //...
    }
    function no(err){
        let errCode=err.response.data.errCode;
        let errMsg=err.response.data.errMsg;
        if(errCode===500&&errMsg=='Invalid token'){
            if(unLoginIsShow == false){
                unLoginIsShow = true;
                //showMessage
            }
        }
        //...
    }
    return { ok, no }
}());
axiosToken.interceptors.response.use(then.ok,then.no)
新手上路,请多包涵

我是直接用window.location.reload 刷新的方法,嗯,是有点粗暴

if (retCode === '100014') {
        // Message.error({
        //   showClose: true,
        //   message: retDesc || '账号未登陆或会话超时',
        // });
        // removeItemAll();
        // router.push({
        //   name: 'login',
        // });
        MessageBox.confirm(retDesc, '会话超时', {
          confirmButtonText: '确定',
          type: 'warning',
          showCancelButton: false,
          showClose: false,
          customClass: 'btn-center',
        }).then(() => {
          removeItemAll();
          window.location.reload();
        }).catch(() => {
          //
        });
      } else {
        // throw new Error(error);
      }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题