资讯专栏INFORMATION COLUMN

axios基于常见业务场景的二次封装

JasinYip / 1569人阅读

摘要:是一个基于的库,可以用在浏览器和中。我在最近的几个项目中都有使用,并基于根据常见的业务场景封装了一个通用的服务。业务场景全局请求配置。请求携带,权限错误统一管理。

axios

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

业务场景:

全局请求配置。

get,post,put,delete等请求的promise封装。

全局请求状态管理。

取消重复请求。

路由跳转取消当前页面请求。

请求携带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://www.ucloud.cn/yun/108504.html

相关文章

  • axios基于常见业务场景二次封装(更新)

    摘要:时隔一年再次更新下根据项目下常见业务场景对的二次封装功能实现兼容浏览器避免缓存减少或更新重复请求接口域名使用环境变量全局状态可关闭的全局错误提醒可开启携带全局分页参数拦截器请求拦截器请求开始请求出错响应拦截器请求结束请求错误处理网络请求中, 时隔一年再次更新下根据vue项目下常见业务场景对axios的二次封装 功能实现:1.兼容ie浏览器避免缓存2.减少或更新重复请求3.接口域名使用环...

    dailybird 评论0 收藏0
  • axios 二次封装(拦截重复请求、异常统一处理)

    摘要:拦截重复请求如何标识每个请求下面函数,通过一个请求参数中的请求传递参数或请求传递参数来表示每一个请求。 一直想封装一下 axios, 可以方便项目中使用,今天有时间,就好好研究了一下。 源码: // util/axios.js import axios from axios const pending = {} const CancelToken = axios.CancelTok...

    luzhuqun 评论0 收藏0
  • 如何构建通用存储中间层

    摘要:并且数据同步后默认会保存下来,这样下次再请求时存储层中就有数据了。以下参数会传到中这么一来,存储层就和接口层对接起来了。五支持永久保存在某些场景下,可能不方便写过期时间,这时默认可以传递,标记该数据永不过期。 零、问题的由来 开门见山地说,这篇文章【又】是一篇安利软文~,安利的对象就是 tua-storage。 顾名思义,这就是一款存储数据的工具。 用 tua-storage 好处大大...

    hersion 评论0 收藏0
  • axios入门实践

    摘要:使用了拦截器处理相关问题,这样就不再需要使用来做错误的处理。万恶的拦截器一些处理无论是对成功的处理还是对失败的处理,如果拦截器不抛出错误,那么终将还会执行里面处理请求成功的函数,即使你返回。 一 前言 本文适合刚接触axios或者使用过几次的同学来分享交流一些入门经验,本文同样适用熟悉axios的同学来作为参考手册。默认你已经看过axios的相关文档:axios文档 GitHub,通过...

    kamushin233 评论0 收藏0
  • 如何构建通用 api 中间层

    摘要:是在收到响应后执行的函数,可以不用返回。一步步介绍了如何构建以及使用中间层,来统一管理接口地址,最后还介绍了下中间件等高级功能。 零、问题的由来 开门见山地说,这篇文章是一篇安利软文~,安利的对象就是最近搞的 tua-api。 顾名思义,这就是一款辅助获取接口数据的工具。 发请求相关的工具辣么多,那我为啥要用你呢? 理想状态下,项目中应该有一个 api 中间层。各种接口在这里定义,业务...

    BingqiChen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<