axios封装

封装取消请求逻辑

取消请求场景:

  • 当请求发送了多次,需要取消之前的请求
  • 当路由切换时,需要取消上个路由中未完成的请求

封装储存请求,清除请求方法

/** 声明一个对象 用于存储每个请求的标识 和 取消函数 */
const pending = new Map()
/** CancelToken 是 axios自带的取消请求函数 **/
let CancelToken = axios.CancelToken

/**
 * 添加请求
 * @param {Object} config 
 */
 const addPending = (config) => {
 /** 加上参数识别,同个接口可能请求多次的情况 **/
  const url = [ config.method, config.url, qs.stringify(config.params), qs.stringify(config.data) ].join('&')
  config.cancelToken = new CancelToken((cancel)=>{
    pending.set(url, cancel)
 });
}

/**
 * 移除请求
 * @param {Object} config 
 */
 const removePending = (config) => {
  const url = [ config.method, config.url, qs.stringify(config.params), qs.stringify(config.data) ].join('&')
  /** 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除 */
  if (pending.has(url)) {
    const cancel = pending.get(url)
    cancel(url)
    pending.delete(url)
  }
}

/**
 * 清空 pending 中的请求(在路由跳转时调用)
 */
export const clearPending = () => {
  for (const [url, cancel] of pending) {
    cancel(url)
  }
  pending.clear()
}

axios拦截器

把上面封装好的方法放到axios拦截器中

/** 
 * request 拦截器
 */
instance.interceptors.request.use(config => {
  /** 可以在请求响应器设置接口的 headers */
  const TOKEN= getToken() || '';
  config.headers = {
    TOKEN,
    'Content-Type': config.contenType ? config.contenType : 'application/json;charset=UTF-8'
  }
  /** 在请求开始前,对之前的请求做检查取消操作 */
  removePending(config)
  /** 将当前请求添加到 pending 中 */
  addPending(config)
  return config
}, error => {
  return Promise.reject(error)
})

/**
 * response 拦截器
 */
 instance.interceptors.response.use(response => {
  /** 在请求结束后,移除本次请求 */
  removePending(response.config)
  /** 在这里可以做相关状态处理,比如登录失效,跳转登录页面等 **/
  if (response.data.code === -100) {
    /** 清空用户缓存信息 */
    store.dispatch('user/logout')
    /** 跳转到登录页 */
    router.replace('/login?redirect=' + encodeURIComponent(window.vm.$route.fullPath))
  }
  return response.data
}, error => {
  /** 判断终止请求的不返回error **/
  if (axios.isCancel(error)) {
    console.log('repeated request: ' + error.message)
  } else {
    // handle error code
    return Promise.reject(error)
  }
})

/** 
 * 使用封装好的 axios,并暴露出去 
**/
const server = (ajaxParams) => {
  if (typeof ajaxParams !== 'object' || Array.isArray(ajaxParams)) throw new Error('参数类型必须是object,请检查')
  /** 合并请求参数 */
  let parame_ = Object.assign({}, ajaxParams.data || {})
  const method = ajaxParams.method === 'GET' ? 'params' : 'data';
  /** 判断 是否为表单请求 Content-Type:multipart/form-data */
  if (!ajaxParams.contenType) {
    ajaxParams[method] = parame_
  } else {
    /** 非文件/图片上传 并且需要表单上传参数 */
    /** 表单请求参数需要序列化 */
    if (!ajaxParams.data instanceof FormData) {
      ajaxParams[method] = qs.stringify(parame_)
    }
  }  
  return instance(ajaxParams)
}
export default server

使用

在main.js中引入并挂载

import server from '@/assets/js/request.js'
Vue.use($ajax);

在文件中使用

/** 普通请求 **/
this.$ajax({
   url: '',
   method: 'POST',
   data: {}
 }).then((res) => {}).catch(err => {});

/** 实例 图片/文件上传 **/
let formData = new FormData()
formData.append("imageFile", file.file)
this.$ajax({
  url: '',
  method: 'POST',
  contenType: 'multipart/form-data',
  data: formData
}).then((res) => {}).catch(err => {});

/** 表单请求 **/
this.$ajax({
  url: '',
  method: 'POST',
  contenType: 'multipart/form-data',
  data: {}
}).then((res) => {}).catch(err => {})

参考文章 https://segmentfault.com/a/1190000021290514

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值