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

axios基于常见业务场景的二次封装的更多相关文章

  1. wpf企业级开发中的几种常见业务场景

    前阵子在公司弄个内部的进销存管理系统,从了解需求.系统设计到编码,大约耗费了两个月时间,后来公司有了其他的安排,这东西就算黄了.顺便吐槽一下,厂里的一些人说话真心不顾别人感受,邮件啥的没一句舒服的.不 ...

  2. android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件

    网络请求是全部App都不可缺少的功能,假设每次开发都重写一次网络请求或者将曾经的代码拷贝到新的App中,不是非常合理,出于此目的,我希望将整个网络请求框架独立出来,与业务逻辑分隔开,这样就能够避免每次 ...

  3. 基于bootstrap table配置的二次封装

    准备 jQuery js css 引用完毕 开始 如果对bootstrap table 的方法与事件不熟悉: Bootstrap table方法,Bootstrap table事件 <table ...

  4. Vue.js 自定义组件封装实录——基于现有控件的二次封装(以计时器为例)

    在本人着手开发一个考试系统的过程中,出现了如下一个需求:制作一个倒计时的控件显示在试卷页面上.本文所记录的就是这样的一个过程. 前期工作 对于这个需求,自然我想到的是有没有现成的组件可以直接使用(本着 ...

  5. Redis常见业务场景应用

    一定时间范围内不可重复发短信问题 Redis实现消息队列 Redis实现Session共享 ...

  6. 基于bootstrap模态框的二次封装

    一.参数设置 $.beamDialog(options); var defaults = { title:'标题', content:'内容', showCloseButton:true, //显示关 ...

  7. 基于ant design form的二次封装

    // standardForm.js import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; ...

  8. python+selenium十:基于原生selenium的二次封装

    from selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium ...

  9. element el-table表格的vue组件二次封装(附表格高度自适应)

    基于vue的el-table表格二次封装组件方法 前言 在公司实习使用vue+element-ui框架进行前端开发,使用表格el-table较为多,有些业务逻辑比较相似,有些地方使用的重复性高,如果多 ...

随机推荐

  1. 【2018.10.1】「JOI 2014 Final」年轮蛋糕

    题面 一看到求“最小值的最大值”这种问题,就能想到二分了. 二分答案,然后我们要把一圈分成三块,使这三块的大小都$\geq mid$.做法是把环展开成2倍长度的链,先钦定一个起点,然后根据前缀和再二分 ...

  2. Spoj-ODDDIV Odd Numbers of Divisors

    Given a positive odd integer K and two positive integers low and high, determine how many integers b ...

  3. Laravel 5 Form 和 HTML 的使用

    最近在用 laravel 5 做例子,在做到表单的时候,习惯性的使用 Form::open() 结果发现提示错误,没有这个类, 好吧,找了找,发现 在laravel 5 中,把 from 和 html ...

  4. UVa10234 Race

    递推,设有i个人排在第一名,剩下的人排在后面,方案有f[i]种,则f[i]=sum(c[n][i]*f[n-i]) 1<=i<=n /*by SilverN*/ #include<a ...

  5. UVa1363 Joseph's Problem

    把整个序列进行拆分成[k,k/2),[k/2, k/3), [k/3,k/4)...k[k/a, k/b)的形式,对于k/i(整除)相同的项,k%i成等差数列. /*by SilverN*/ #inc ...

  6. Java面试题集(六)

    以下为框架补充部分: Struts 2中,Action通过什么方式获得用户从页面输入的数据,又是通过什么方式把其自身的数据传给视图的? Action从页面获取数据有三种方式: ①通过Action属性接 ...

  7. 标准C程序设计七---01

    Linux应用             编程深入            语言编程 标准C程序设计七---经典C11程序设计    以下内容为阅读:    <标准C程序设计>(第7版) 作者 ...

  8. Linux主机被SSH精神病(Psychos)暴力攻破后成为肉鸡的攻防过程

    近日公司局域网突然变得非常慢,上网受到很大影响,不仅仅是访问互联网慢,就连访问公司内部服务器都感到异常缓慢.于是对本局域网网关进行测试:   $ ping 10.10.26.254   发现延时很大, ...

  9. hdu - 2667 Proving Equivalences(强连通)

    http://acm.hdu.edu.cn/showproblem.php?pid=2767 求至少添加多少条边才能变成强连通分量.统计入度为0的点和出度为0的点,取最大值即可. #include & ...

  10. POJ 1991 Turning in Homework(区间DP)

    题目链接 Turning in Homework 考虑区间DP $f[i][j][0]$为只考虑区间$[i, j]$且最后在$a[i]$位置交作业的答案. $f[i][j][1]$为只考虑区间$[i, ...