zoukankan      html  css  js  c++  java
  • axios基于常见业务场景的二次封装

    axios

    axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
    在前端框架中的应用也是特别广泛,不管是vue还是react,都有很多项目用axios作为网络请求库。
    我在最近的几个项目中都有使用axios,并基于axios根据常见的业务场景封装了一个通用的request服务。

    业务场景:

    1. 全局请求配置。
    2. get,post,put,delete等请求的promise封装。
    3. 全局请求状态管理。
    4. 取消重复请求。
    5. 路由跳转取消当前页面请求。
    6. 请求携带token,权限错误统一管理。

    默认配置


    定义全局的默认配置

    
    axios.defaults.timeout = 10000 //超时取消请求
    axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
    axios.defaults.baseURL = process.env.BASE_URL //挂载在process下的环境常量,在我另一篇文章有详细说明
    

    如何定义多环境常量


    自定义配置(非常见业务场景,仅作介绍)

    
    // 创建实例时设置配置的默认值
    var instance = axios.create({
      baseURL: 'https://api.another.com'
    });
    // 在实例已创建后修改默认值
    instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
    

    优先级:自定义配置 > 默认配置

    请求及响应拦截器

    请求拦截器及取消重复请求

    
    // 请求列表
    const requestList = []
    // 取消列表
    const CancelToken = axios.CancelToken
    let sources = {}
    axios.interceptors.request.use((config) => {
      //将请求地址及参数作为一个完整的请求
      const request = JSON.stringify(config.url) + JSON.stringify(config.data)
      config.cancelToken = new CancelToken((cancel) => {
        sources[request] = cancel
      })
      //1.判断请求是否已存在请求列表,避免重复请求,将当前请求添加进请求列表数组;
      if(requestList.includes(request)){
        sources[request]('取消重复请求')
      }else{
        requestList.push(request)
        //2.请求开始,改变loading状态供加载动画使用
        store.dispatch('changeGlobalState', {loading: true})
      }
      //3.从store中获取token并添加到请求头供后端作权限校验
      const token = store.getters.userInfo.token
      if (token) {
        config.headers.token = token
      }
      return config
    }, function (error) {
      return Promise.reject(error)
    })
    

    1.请求拦截器中将所有请求添加进请求列表变量,为取消请求及loading状态管理做准备;当请求列表已存在当前请求则不响应该请求。
    2.请求一旦开始,就可以开启动画加载效果。
    3.用户登录后可以在请求头中携带token做权限校验使用。


    响应拦截器

    
    axios.interceptors.response.use(function (response) {
      // 1.将当前请求中请求列表中删除
      const request = JSON.stringify(response.config.url) + JSON.stringify(response.config.data)
      requestList.splice(requestList.findIndex(item => item === request), 1)
      // 2.当请求列表为空时,更改loading状态
      if (requestList.length === 0) {
        store.dispatch('changeGlobalState', {loading: false})
      }
      // 3.统一处理权限认证错误管理
      if (response.data.code === 900401) {
        window.ELEMENT.Message.error('认证失效,请重新登录!', 1000)
        router.push('/login')
      }
      return response
    }, function (error) {
      // 4.处理取消请求
      if (axios.isCancel(error)) {
        requestList.length = 0
        store.dispatch('changeGlobalState', {loading: false})
        throw new axios.Cancel('cancel request')
      } else {
        // 5.处理网络请求失败
        window.ELEMENT.Message.error('网络请求失败', 1000)
      }
      return Promise.reject(error)
    })
    

    1.响应返回后将相应的请求从请求列表中删除
    2.当请求列表为空时,即所有请求结束,加载动画结束
    3.权限认证报错统一拦截处理
    4.取消请求的处理需要结合其他代码说明
    5.由于项目后端并没有采用RESTful风格的接口请求,200以外都归为网络请求失败

    promise封装

    
    const request = function (url, params, config, method) {
      return new Promise((resolve, reject) => {
        axios[method](url, params, Object.assign({}, config)).then(response => {
          resolve(response.data)
        }, err => {
          if (err.Cancel) {
            console.log(err)
          } else {
            reject(err)
          }
        }).catch(err => {
          reject(err)
        })
      })
    }
    
    const post = (url, params, config = {}) => {
      return request(url, params, config, 'post')
    }
    
    const get = (url, params, config = {}) => {
      return request(url, params, config, 'get')
    }
    //3.导出cancel token列表供全局路由守卫使用
    export {sources, post, get}
    

    1.axios cancel token API
    2.存入需要取消的请求列表导出给导航守卫使用
    3.路由发生变化的时候取消当前页面还没有返回结果的请求,在复杂的页面中请求可能会有很多个,增加取消请求的功能可以让页面切换的时候不卡顿。
    /src/router.js

    
    ...
    import { sources } from '../service/request'
    ...
    router.beforeEach((to, from, next) => {
      document.title = to.meta.title || to.name
        //路由发生变化时取消当前页面网络请求
      Object.keys(sources).forEach(item => {
        sources[item]('取消前页面请求')
      })
      for (var key in sources) {
        delete sources[key]
      }
      next()
    })
    

    request.js完整代码:

    
    
    
    // 引入网络请求库 https://github.com/axios/axios
    
    import axios from 'axios'
    import store from '../store'
    import router from '../router'
    
    // 请求列表
    const requestList = []
    // 取消列表
    const CancelToken = axios.CancelToken
    let sources = {}
    
    // axios.defaults.timeout = 10000
    axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
    
    axios.defaults.baseURL = process.env.BASE_URL
    
    axios.interceptors.request.use((config) => {
      const request = JSON.stringify(config.url) + JSON.stringify(config.data)
    
      config.cancelToken = new CancelToken((cancel) => {
        sources[request] = cancel
      })
    
      if(requestList.includes(request)){
        sources[request]('取消重复请求')
      }else{
        requestList.push(request)
        store.dispatch('changeGlobalState', {loading: true})
      }
    
      const token = store.getters.userInfo.token
      if (token) {
        config.headers.token = token
      }
    
      return config
    }, function (error) {
      return Promise.reject(error)
    })
    
    axios.interceptors.response.use(function (response) {
      const request = JSON.stringify(response.config.url) + JSON.stringify(response.config.data)
      requestList.splice(requestList.findIndex(item => item === request), 1)
      if (requestList.length === 0) {
        store.dispatch('changeGlobalState', {loading: false})
      }
      if (response.data.code === 900401) {
        window.ELEMENT.Message.error('认证失效,请重新登录!', 1000)
        router.push('/login')
      }
      return response
    }, function (error) {
      if (axios.isCancel(error)) {
        requestList.length = 0
        store.dispatch('changeGlobalState', {loading: false})
        throw new axios.Cancel('cancel request')
      } else {
        window.ELEMENT.Message.error('网络请求失败', 1000)
      }
      return Promise.reject(error)
    })
    
    const request = function (url, params, config, method) {
      return new Promise((resolve, reject) => {
        axios[method](url, params, Object.assign({}, config)).then(response => {
          resolve(response.data)
        }, err => {
          if (err.Cancel) {
            console.log(err)
          } else {
            reject(err)
          }
        }).catch(err => {
          reject(err)
        })
      })
    }
    
    const post = (url, params, config = {}) => {
      return request(url, params, config, 'post')
    }
    
    const get = (url, params, config = {}) => {
      return request(url, params, config, 'get')
    }
    
    export {sources, post, get}
    
    
    

    以上。

    来源:https://segmentfault.com/a/1190000016474460

  • 相关阅读:
    monkeyrunner 进行多设备UI测试
    python Pool并行执行
    python 字符串函数
    python Map()和reduce()函数
    python re模块使用
    3.6 C++继承机制下的构造函数
    3.5 C++间接继承
    3.4 C++名字隐藏
    3.3 C++改变基类成员在派生类中的访问属性
    3.2 C++继承方式
  • 原文地址:https://www.cnblogs.com/qixidi/p/10137924.html
Copyright © 2011-2022 走看看