乐趣区

关于vue.js:壁虎科技Vue中封装axios的取消请求事情

前言

须要勾销反复申请的场景:

  • 比方输入框搜寻须要勾销上一次的反复申请
  • tab 切换频繁获取数据列表接口时,接口反复申请
  • 就是用户频繁切换操作时,咱们调用都是同一个接口的时候,就需要先勾销上一次的接口申请,只申请用户最初一次操作的接口,不然雷同的接口反复申请,接口是异步的,到时就容易拿到数据不是最初一次操作想要的数据了

axios 自身就封装了勾销事件

axios 中文文档 勾销事件

axios 勾销事件代码如下

  • 办法一、能够应用 CancelToken.source 工厂办法创立 cancel token,像这样:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {cancelToken: source.token}).catch(function(thrown) {if (axios.isCancel(thrown)) {console.log('Request canceled', thrown.message);
  } else {// 处理错误}
});

axios.post('/user/12345', {name: 'new name'}, {cancelToken: source.token})

// 勾销申请(message 参数是可选的)source.cancel('Operation canceled by the user.');
  • 办法二、还能够通过传递一个 executor 函数到 CancelToken 的构造函数来创立 cancel token:
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {cancelToken: new CancelToken(function executor(c) {
    // executor 函数接管一个 cancel 函数作为参数
    cancel = c;
  })
});

// cancel the request
cancel();

独自应用 axios 的时候,两个办法都能够,然而封装好 axios 办法在 vue 中全局调用时,办法一有个问题,axios 的 cancel 办法会把行将要收回的申请勾销掉,所以用第二个办法

残缺 axios 封装代码如下:

import axios from 'axios'
import UserModel from '../models/user'

// 接口前缀
const PREFIX = {
  mock: 'https://yapi.comliq.net/mock/31/', // yapi mock 地址
  development: 'http://xxx/', // qa 环境
  production: 'http://xxx/', // 生产环境
}
const env = process.env.NODE_ENV
let interfacePrefix = PREFIX[env] || PREFIX.production // 接口前缀

/**
 * config 自定义配置项
 * @param withoutCheck 不应用默认的接口状态校验,间接返回 response
 * @param returnOrigin 是否返回整个 response 对象,为 false 只返回 response.data
 * @param mock 是否应用 mock 服务
 * @param timeout 接口申请超时工夫,默认 10 秒
 * @param isCancelRequest 是否能够勾销申请
 */
const configDefault = {
  returnOrigin: false,
  withoutCheck: false,
  mock: false,
  timeout: 10000
}

// 创立申请器
const service = axios.create(Object.assign({
  baseURL: '',
  responseType: 'json',
  headers: {'Content-Type': 'application/json;charset=utf-8',},
}, configDefault))


// 增加申请拦截器
service.interceptors.request.use(
  request => {
    const reqData = request.data || request.params
    if (reqData && !request.canEmpty) { // 对申请参数进行解决,革除空参数
      request.data = deleteEmpty(reqData)
    }

    // 检测接口,依据环境主动切换前缀
    if (request.url.indexOf('http') === -1) {if (request.url[0] === '/') {request.url = request.url.substr(1)
      }
      request.url = `${env !== 'production' && request.mock ? PREFIX.mock : interfacePrefix}${request.url}`
    }

    // 若有做鉴权 token,须要申请头主动加上 token, 这个 token 本人封装获取的
    request.headers.accessToken = UserModel.getToken()

    return request
  },
  error => {return Promise.reject(error)
  },
)

// object 对象寄存每次 new CancelToken 生成的办法
let source = {}

// 每次申请前都会把 path 放在此数组中,响应胜利后革除此申请 path
let requestList = []

// 定义勾销办法
function cancelRequest(path, allCancel) {
  // 申请列表里存在此 path,即发动反复申请,把之前的申请勾销掉
  if (path && requestList.includes(path) && typeof source[path] === 'function') {source[path]('终止申请')
  } else if (!path && allCancel) {
    // allCancel 为 true 则申请列表里的申请全副勾销
    requestList.forEach(el => {source[el]('批量终止申请')
    })
  }
}

// 增加响应拦截器
service.interceptors.response.use(
  res => {
    // 获取申请的 api
    const path = JSON.stringify(res.config.url)
    // 申请实现后,将此申请从申请列表中移除
    requestList = requestList.filter(item => !path.includes(item))
    // HTTP 状态码 2xx 状态入口,data.code 为 200 示意数据正确,无任何谬误
  },
  error => { // 非 2xx 状态入口
    return Promise.reject(error)
  },
)

// 这里只做 post 封装演示,大家能够本人封装其余申请办法
function requestFn(method, path, params = {}, options = {}) {
  // 勾销上一次申请
  if (requestList.length) {cancelRequest(path)
  }
  // 设置 isCancelRequest 为 ture, 申请前将 path 推入 requestList
  if (options.isCancelRequest) {requestList.push(path)
  }

  if (method === 'post') {
    return service.post(path, params, {
      cancelToken: new axios.CancelToken(c => {source[path] = c
      }),
      ...options
    })
  }
}

export const api = {
  axios: service, // 原始 axios 对象

  // 从新封装 get 函数,对立应用形式
  get: (path, data, config) => service.get(path, { params: data, ...config}),
  delete: (path, data, config) => service.delete(path, { data, ...config}),

  post: (path, data, config) => requestFn('post', path, data, config),
  put: (path, data, config) => service.put(path, data, config),
}

export default api

参考文献:

Vue 中封装带有勾销申请的 axios

退出移动版