使用axios拦截器解决【前端并发冲突】

目录

 

项目中实际应用:

axios请求添加统一拦截

1.interceptors   

项目中实际应用:

2.cancel token:

request请求的全部代码

总结


前言

项目中有一些接口调用第三方的时候相应会很慢,会出现短时间内重复请求

还有用户在短时间内多次提交数据

都会产生并发冲突这种在前端可以做一次拦截

目前我总结的有两种方法:

第一种方案:在提交确认按钮上添加loading等待

第二种方案:在axios请求做统一的接口重复提交拦截

下面具体说明两种情况怎么使用


提交确认按钮上添加loading等待

这种方式比较简单,主要就是平时的编码习惯,在.vue页面请求接口的时候在请求之前添加loading:true,接口调用成功后将loading:false,这也是比较简单而且粗暴的解决方案,可谓白猫黑猫,抓到老鼠就是好猫

项目中实际应用:

axios请求添加统一拦截

项目中出现并发的情况比较多,当我们项目做到一定的程度的时候,要是按照上面添加loading的方式去解决并发问题显然已经不是最优的解决方案了

接口每次的请求都会出现并发的情况,如果我们的项目中axios是统一进行二次封装的,那就可以在统一请求的地方添加请求拦截,自动处理重复请求,这样也是大大优化了我们的业务代码

axios发送http请求的时候官方有两个核心的拦截请求的API:

1.interceptors   

n. 截击舰,[航][军] 截击机;拦截器;拦截者(interceptor的复数)

拦截器有两种拦截器(请求拦截和相应拦截)我们可以在这两个地方去做处理

项目中实际应用:

 

2.cancel token:

调用 cancel token API 能够取消请求。官网提供了两种方式来构建 cancel token,咱们采用这种方式:经过传递一个 executor 函数到 CancelToken 的构造函数来建立 cancel token,方便在上面的请求拦截器中检测到重复请求能够当即执行:

let cancel
config.cancelToken = new axios.CancelToken(function (c) {
   cancel = c
})

request请求的全部代码

import axios from 'axios'
import { getToken } from '_utils/token'

export default class httpRequest {
  constructor (baseUrl = '') {
    this.baseUrl = baseUrl
    // 存储请求队列
    this.queue = []
  }

  getInsideConfig () {
    const config = {
      baseURL: this.baseUrl,
      // 请求超时时间
       timeout: 10 * 1000,
      headers: {
        'Content-Type': 'application/json; charset=utf-8',
        'X-URL-PATH': location.pathname
      },
    }
    return config
  }

  // 对特殊配置要求做配置修改--可以针对特殊接口添加配置
  changeConfig (options) {
    let tempOptions = options
    return tempOptions
  }

  // 销毁请求实例
  destroy (config) {
      let matchIndex = findMatchIndex(this.queue, config)
      if (matchIndex !== -1) {
        this.queue.splice(matchIndex, 1)  //接口请求成功后在请求队列的数组中删除掉
      }
    LoadingBar.finish()
    store.dict.state.loading = false
  }

  // 请求拦截
  interceptors (instance, url, method) {
    // 添加请求拦截器
    instance.interceptors.request.use(
      config => {
        if (config.isLoading) {
          // 这里可以添加全局loading...   可以将接口的状态添加在store中全局使用
        }

        // 处理重复请求
          let cancel
          config.cancelToken = new axios.CancelToken(function (c) {
            cancel = c
          })

          let matchIndex = findMatchIndex(this.queue, config)
          if (matchIndex !== -1) {
            Notice.error({
              title: '提示',
              desc: '请不要重复提交'
            })
            cancel('请求中断')
          } else {

            //判断接口没有重复请求的时候,将接口添加到请求队列中
            this.queue.push({
              url: config.url,
              method: config.method,
              params: config.params
            })
          }
     
        // 请求发送前处理.
        config.headers.authorization = getToken()
        return config
      },
      error => {
        // 请求错误处理
        return Promise.reject(error)
      }
    )

    // 添加响应拦截器
    instance.interceptors.response.use(
      res => {
        let { config } = res
        if (config.isLoading) {
          // 请求响应后销毁请求实例
          this.destroy(config)
        }
        let { data } = res
        // code 验证
        let { code } = data
        let { state } = data
        if (code === 200) {
          // 无权限
          if (code === 'code_400') {
         
            return Promise.reject(data)
          }
          // 错误401 token无效 删除token 返回鉴权中心(登录页)
          if (code === 401) {
            logoff()
            // 其他错误 处理
          }
          if (code === 'code_500') {

            return Promise.reject(data)
          }
          if (code === 'code_406') { //请求参数不正确!
      
            return Promise.reject(data)
          }
        }
        if (state === '500') { //服务器错误
         
        }
        return data
      },
      error => {
        LoadingBar.error()
        // 响应错误处理
     
        return Promise.reject(error)
      }
    )
  }

  request (options) {
    const instance = axios.create()
    // 合并options
    options = this.changeConfig(Object.assign(this.getInsideConfig(), options))
    // 注册拦截器
    this.interceptors(instance, options.url, options.method)
    // 返回实例
    return instance(options)
  }
}

function findMatchIndex (map, config) {
  return map.findIndex(item => {
    if (
      config.url.includes(item.url) &&
      item.method === config.method &&
      diff(item.params, config.params)
    ) {
    }
    return (
      config.url.includes(item.url) &&
      item.method === config.method &&
      diff(item.params, config.params)
    )
  })
}

function diff (obj1, obj2) {
  if (Object.keys(obj1).length !== Object.keys(obj2).length) {
    return false
  }
  let obj1Keys = Object.keys(obj1)
  for (let i = 0; i < obj1Keys.length; i++) {
    if (obj1[obj1Keys[i]] !== obj2[obj1Keys[i]]) {
      return false
    }
  }
  return true
}

总结

并发请求比较常见,在接口请求出统一处理,但是在具体的业务中,出现接口请求时间比较长的接口还是要通过全局的loading状态去控制提交数据时的按钮,按钮上添加loading或者disable掉,这个根据自己的业务具体对待

 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值