vue axios封装之取消请求

在最美好的年华,没有遇到爱情,只遇到了疫情

应用环境,当我们项目中使用模糊匹配查询列表的时候,输入框中输入关键字,我们就会根据关键字调接口查询数据,如果输入的很快,接口反应不是很快,那么就会出现搜索出来的数据和输入的关键字不匹配的情况。这时候我们就需要配置axios请求的CancelToken来取消还没有响应完的接口,直接根据最新输入查询接口,匹配最新的结果
vue axios封装之取消请求_第1张图片

引入axios定义需要的变量

// 引入axios
import axios from 'axios'
...
let cancel
let promiseArr = {}
const CancelToken = axios.CancelToken

在请求拦截器中配置

// 取消请求
  if (promiseArr[config.url]) {
    promiseArr[config.url]('操作取消')
    promiseArr[config.url] = cancel
  } else {
    promiseArr[config.url] = cancel
  }

在get/post/put请求中配置

...
axios.get(url, {
      params: params,
      cancelToken: new CancelToken(c => {
        cancel = c
      })
    }).then(res => {
    ...
axios.post(
      url,
      params,
      {
        cancelToken: new CancelToken(c => {
          cancel = c
        })
      }
    ).then(res => {

vue中axios封装完整代码

// 引入axios
import axios from 'axios'
// 引入qs模块,用来序列化post类型的数据,后面会提到
// import QS from 'qs'
import store from '@/store/index'
import router from '@/router/index'
// elementUi提示组件。
import { Message } from 'element-ui'
// import {LoadingBar} from 'iview'
let cancel
let promiseArr = {}
const CancelToken = axios.CancelToken
// 环境的切换
console.log(process.env.NODE_ENV, process.env.ENV_CONFIG, '环境参数')
if (process.env.NODE_ENV === 'development') {
  console.log(router, store, 'http.js中的路由器信息')
  axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate'
} else if (process.env.NODE_ENV === 'testing') {
  axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate'
} else if (process.env.NODE_ENV === 'production') {
  axios.defaults.baseURL = 'https://www.bangying.tech/api'
}
// 设置请求最大时长
axios.defaults.timeout = 50000
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
axios.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8'
axios.defaults.headers.common['By-User-Info'] = localStorage.getItem('userInfo_admin') ? JSON.parse(localStorage.getItem('userInfo_admin')).user_id : ''
axios.defaults.withCredentials = true
// 请求拦截器
axios.interceptors.request.use(config => {
  // 如果不是登录接口,或者微信分享接口,都需要验证token, 隐私策略
  // if (window.location.hash.indexOf('login') === -1 && window.location.hash.indexOf('wechat-share') === -1 && window.location.hash.indexOf('private') === -1) {
  //   const token = store.state.userInfo.Authorization
  //   token && (config.headers.Authorization = token)
  // }
  // 取消请求
  if (promiseArr[config.url]) {
    promiseArr[config.url]('操作取消')
    promiseArr[config.url] = cancel
  } else {
    promiseArr[config.url] = cancel
  }
  // 配置request请求头header中的Authorization,如果登陆了就有Authorization就设置一下
  if (store.state.userInfo && store.state.userInfo.Authorization) {
    const token = store.state.userInfo.Authorization
    token && (config.headers.Authorization = token)
  }
  return config
}, error => {
  Message.error({
    message: '请求接口出错',
    duration: 3000
  })
  return Promise.error(error)
})

// 响应拦截器
axios.interceptors.response.use(response => {
  // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据
  // 否则的话抛出错误
  if (response.status === 200) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(response)
  }
}, error => {
  if (error.response.status) {
    switch (error.response.status) {
      // 401: 未登录
      // 未登录则跳转登录页面,并携带当前页面的路径
      // 在登录成功后返回当前页面,这一步需要在登录页操作。
      case 401:
        // Message.error({
        //   message: '无权限',
        //   duration: 1000
        // })
        // window.location.href = store.getters.base_url + 'new-home/#/login'
        // router.replace({name: 'login'})
        break
      // 403 token过期
      // 登录过期对用户进行提示
      // 清除本地token和清空vuex中token对象
      // 跳转登录页面
      case 403:
        // Message.error({
        //   message: '登录过期,请重新登录',
        //   duration: 1000
        // })
        // 清除token
        // localStorage.removeItem('token')
        // store.commit('loginSuccess', null)
        // 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
        // window.location.href = store.getters.base_url + 'new-home/#/login'
        localStorage.clear()
        store.dispatch('loginOut')
        break
        // 404请求不存在
      case 404:
        Message.error({
          message: '网络请求不存在',
          duration: 1500
        })
        break
      // 其他错误,直接抛出错误提示
      default: {
        // Message.error({
        //   message: error.response.data.message,
        //   duration: 1500
        // })
      }
    }
    return Promise.reject(error.response)
  }
})

export function get (url, params, config) {
  if (config) {
    axios.defaults.headers.post['Content-Type'] = 'multipart/form-data'
  }
  // LoadingBar.start()
  let phpApi = false
  // get方法中使用php接口地址
  if (
    url === '/index.php/file/upload_token' ||
    url === '/index.php/home_page/currency' ||
    url === '/index.php/count_channel/channel_province_count' ||
    url === '/index.php/count_channel/channel_history_count' ||
    url === '/index.php/count_channel/channel_role_count' ||
    url === '/index.php/count_channel/channel_newadd_count' ||
    url === '/index.php/count_project/project_num_count' ||
    url === '/index.php/count_project/department_count' ||
    url === '/index.php/count_project/project_count_total' ||
    url === '/index.php/user/department' ||
    url === '/index.php/count_project/project_department_num_count' ||
    url === '/index.php/count_project/province_count' ||
    url === '/index.php/count_project/clue_source_count' ||
    url === '/index.php/count_project/stage_count' ||
    url === '/index.php/count_project/reason_count' ||
    url === '/index.php/count_project/project_time_count' ||
    url === '/index.php/count_project/project_time_department_count' ||
    url === '/index.php/count_project/duban_money_count' ||
    url === '/index.php/count_project/refuse_count' ||
    url === '/index.php/count_project/project_evaltime_count' ||
    url === '/index.php/count_project/accept_count'
  ) {
    phpApi = true
  } else {
    phpApi = false
  }

  // 线上环境
  if (process.env.NODE_ENV === 'production') {
    // 上传token
    if (phpApi) {
      axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
    } else {
      axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
    }
  } else {
    // 开发测试环境
    // 获取上传token
    if (phpApi) {
      axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
    } else {
      axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
    }
  }
  return new Promise(async (resolve, reject) => {
    await axios.get(url, {
      params: params,
      cancelToken: new CancelToken(c => {
        cancel = c
      })
    }).then(res => {
      resolve(res.data)
      // LoadingBar.finish()
    }).catch(err => {
      reject(err.data)
      // LoadingBar.error()
    })
  })
}
export function post (url, params, config) {
  if (config) {
    axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
  }
  // LoadingBar.start()
  console.log(window.location.hash)
  return new Promise((resolve, reject) => {
    // 线上环境
    if (process.env.NODE_ENV === 'production') {
      // php接口
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/login/wechat' ||
        url === '/index.php/login/un_login'

      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
      } else if (url === 'qiniu') {
        axios.defaults.baseURL = ''
        url = 'https://qiniu.pangu.tech/'
      } else {
        // java接口
        axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
      }
    } else {
      // 开发测试环境
      // 如果是php接口
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/login/wechat' ||
        url === '/index.php/login/un_login'
      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
      } else if (url === 'qiniu') {
        axios.defaults.baseURL = ''
        url = 'https://qiniu.pangu.tech/'
      } else {
        // java接口
        axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
      }
    }
    axios.post(
      url,
      params,
      {
        cancelToken: new CancelToken(c => {
          cancel = c
        })
      }
    ).then(res => {
      resolve(res.data)
      // LoadingBar.finish()
    }).catch(err => {
      reject(err.data)
      // LoadingBar.error()
    })
  })
}

export function put (url, params) {
  // LoadingBar.start()
  console.log(window.location.hash)
  return new Promise((resolve, reject) => {
    // 线上环境
    if (process.env.NODE_ENV === 'production') {
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/project/up_status'
      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/prod/pg_app_api'
      } else if (url === 'qiniu') {
        axios.defaults.baseURL = ''
        url = 'https://qiniu.pangu.tech/'
      } else {
        axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
      }
    } else {
      // 开发测试环境
      if (
        url === '/index.php/login/account' ||
        url === '/index.php/project/up_status'
      ) {
        axios.defaults.baseURL = 'https://api.bangying.tech/new_simulate/new_m_api'
      } else {
        axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
      }
    }
    axios.put(
      url,
      params,
      {
        cancelToken: new CancelToken(c => {
          cancel = c
        })
      }
    ).then(res => {
      resolve(res.data)
      // LoadingBar.finish()
    }).catch(err => {
      reject(err.data)
      // LoadingBar.error()
    })
  })
}

export function getAxios () {
  // 线上环境
  if (process.env.NODE_ENV === 'production') {
    axios.defaults.baseURL = 'https://www.bangying.tech/pg-api'
  } else {
    // 开发测试环境
    axios.defaults.baseURL = 'https://mn.bangying.tech/pg-api'
  }
  return axios
}

实践证明这样封装是有问题的

vue axios封装之取消请求_第2张图片

下面展示真正的技术

// 引入axios
import axios from 'axios'

...

// 声明一个数组用于存储每个请求的取消函数和axios标识
let pending = []
const CancelToken = axios.CancelToken
let removePending = (config) => {
  for (let p in pending) {
    if (pending[p].u === config.url + JSON.stringify(config.data) + '&' + config.method) {
      pending[p].f()
      pending.splice(p, 1)
    }
  }
}

...

// 请求拦截器
axios.interceptors.request.use(config => {
// 取消请求
  removePending(config)
  config.cancelToken = new CancelToken((c) => {
    // 这里的axios标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
    pending.push({ u: config.url + JSON.stringify(config.data) + '&' + config.method, f: c })
  })
  
  ...
  
})

...


// 响应拦截器
axios.interceptors.response.use(response => {

  ...
  // 取消响应
  removePending(response.config)
  
  ...
  
})

这样在请求和响应中拦截就可以了

你可能感兴趣的:(vue.js,axios)