2024.05 路由切换时取消上个页面的请求

253 阅读2分钟

实现思路:在进入路由之前,如果之前有存在还未完成的请求则取消掉请求(使用axios.cancel实现),每次发起请求的时候在请求拦截的地方保存请求数据,每次进入路由之前进行清空。

store中新建promiseStore来保存所有需要清空的请求列表

  • 新建promiseStore src\store\modules\promiseStore.js
const promiseStore = {
  state:{
    clearPmsArr: [],
  },
  mutations: {
    pushPmsStack(state, source){
      state.clearPmsArr = [...state.clearPmsArr, source]
    },
    clearPmsStack({clearPmsArr}){
      clearPmsArr && clearPmsArr.forEach(xhr => {
        xhr.cancel('路由跳转取消之前页面的请求')
      });
      clearPmsArr = []
    }
  }
}
​
export default promiseStore

store中注册promiseStore

import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import promiseStore from './modules/promiseStore'
Vue.use(Vuex)
​
export default new Vuex.Store({
  getters,
  modules: {
    promiseStore
  },
})
​
  • 请求拦截的地方进行处理
import axios from 'axios'
import store from '@/store'
const CancelToken = axios.CancelToken
​
axios.interceptors.request.use(
  config => {
    let source = CancelToken.source()
    config.cancelToken = source.token
    // 将请求保存在clearPmsArr中
    store.state.promiseStore.clearPmsArr.push(source)
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

response拦截

// response拦截器
axios.interceptors.response.use(
  response => {
    console.log(response)
    // endLoading();
    const res = response.data
    if (res.code === 401) {
      router.push('/login')
    }
    // 请求成功
    return response
  },
  error => {
    // 无权限
    // console.log(error)
    if (error.code === 'ERR_CANCELED') {
      // 判断为取消请求的时候返回提示信息而不是直接控制台报错,在get请求中根据返回的状态code进行判断是取消请求的时候进行提示
      return Promise.resolve({ statusText: 'OK', status: 200, data: { code: 'cancel', msg: '请求已取消', data: null } })
    }
    if (error.response.status === 401) {
      router.push('/login')
    } else if (error.response.status === 500) {
      errormsg('服务不可用')
    } else {
      console.log(`repsones error: ${error}`) // for debug
      errormsg(error.response.data.msg)
    }
    console.log(error)
    return Promise.reject(error)
  }
)

封装请求方法

/**
 * get 请求
 * @param url
 * @param params
 */
async function get(url, params, isQs, isFormData) {
  return new Promise((resolve, reject) => {
    axios
      .get(url, {
        params: params
      })
      .then(
        response => {
        // 判断拿到的是取消的请求
          if(response.data.code === 'cancel'){
            errormsg(response.data.msg || response.message || '')
          }
          if (response.data.code !== 200) {
            errormsg(response.data.msg || response.message || '')
          }
          resolve({ status: response.data.code === 200, ...response.data })
        },
        err => {
          // console.log('get', err)
          if (!err.data.status) {
            errormsg(err.data.message || err.message || HTTP_ERROR_MSG)
          }
          reject(err)
        }
      )
      .catch(error => {
        console.log(error)
        errormsg(HTTP_ERROR_MSG)
        reject(error)
      })
  })
  // return await request({ url, params, method: 'get' })
}
​
  • 路由拦截地方进行清空请求
router.beforeEach(async (to, from, next) => {
    // 执行清空请求的方法
  store.commit('clearPmsStack')
  NProgress.start();
  //未匹配到的路由
  if (!to.matched || !to.matched.length) {
    next({ name: 'Error404' });
    return;
  }
  let userInfo = Utils.getStorage('userInfo');
  if (to.path === '/login') {
    next();
    return;
  }
  //用户信息存在
  if (!userInfo || Object.keys(userInfo).length === 0) {
    next({ name: 'login' });
    return;
  } else {
    next();
    NProgress.done();
    return;
  }
});
  • 验证,可以看到页面有取消请求的提示,network里面请求也确实被取消了

image-20240619092822152.png

待优化: 优化:

  • 目前这样每个页面如果有多个请求的时候会产生多个提示

    • 取消提示放在控制台打印,不要展示给用户看到
  • 当刚切换页面的时候路由还未完全切换完就已经取消了请求交互不友好