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


Posted in Javascript onSeptember 21, 2018

axios

axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

在前端框架中的应用也是特别广泛,不管是vue还是react,都有很多项目用axios作为网络请求库。

我在最近的几个项目中都有使用axios,并基于axios根据常见的业务场景封装了一个通用的request服务。

npm:

$ npm install axios

bower:

$ bower install axios

Using cdn:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

业务场景:

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

默认配置

定义全局的默认配置

axios.defaults.timeout = 10000 //超时取消请求
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.defaults.baseURL = process.env.BASE_URL

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

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

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

请求及响应拦截器

请求拦截器

// 请求列表
const requestList = []
axios.interceptors.request.use((config) => {
 //1.将当前请求的URL添加进请求列表数组
 requestList.push(config.url)
 //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.请求拦截器中将所有请求的url添加进请求列表变量,为取消请求及loading状态管理做准备
2.请求一旦开始,就可以开启动画加载效果。
3.用户登录后可以在请求头中携带token做权限校验使用。

响应拦截器

axios.interceptors.response.use(function (response) {
 // 1.将当前请求中请求列表中删除
 requestList.splice(requestList.findIndex(item => item === response.config.url), 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 CancelToken = axios.CancelToken
//cancel token列表
let sources = []
const request = function (url, params, config, method) {
 return new Promise((resolve, reject) => {
  axios[method](url, params, Object.assign({}, config, {
  //1.通过将执行程序函数传递给CancelToken构造函数来创建cancel token
   cancelToken: new CancelToken(function executor (c) {
   //2.将cancel token存入列表
    sources.push(c)
   })
  })).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.router.js

...
import { sources } from '../service/request'
...
router.beforeEach((to, from, next) => {
 document.title = to.meta.title || to.name
  //路由发生变化时取消当前页面网络请求
 sources.forEach(item => {
  item()
 })
 sources.length = 0
 next()
})

request.js完整代码:

// 引入网络请求库 https://github.com/axios/axios

import axios from 'axios'
import store from '../store'
import router from '../router'

// axios.defaults.timeout = 10000
const requestList = []

axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'

axios.defaults.baseURL = process.env.BASE_URL
// 自定义拦截器
axios.interceptors.request.use((config) => {
 requestList.push(config.url)
 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) {
 requestList.splice(requestList.findIndex(item => item === response.config.url), 1)
 if (requestList.length === 0) {
  store.dispatch('changeGlobalState', {loading: false})
 }
 if (response.data.code === 900401) {
  window.$toast.error('认证失效,请重新登录!', 1000)
  router.push('/login')
 }
 return response
}, function (error) {
 requestList.length = 0
 store.dispatch('changeGlobalState', {loading: false})
 if (axios.isCancel(error)) {
  throw new axios.Cancel('cancel request')
 } else {
  window.$toast.error('网络请求失败!', 1000)
 }
 return Promise.reject(error)
})

const CancelToken = axios.CancelToken
let sources = []

const request = function (url, params, config, method) {
 return new Promise((resolve, reject) => {
  axios[method](url, params, Object.assign(config, {
   cancelToken: new CancelToken(function executor (c) {
    sources.push(c)
   })
  })).then(response => {
   resolve(response.data)
  }, err => {
   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}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript 写类方式之七
Jul 05 Javascript
JavaScript中各种编码解码函数的区别和注意事项
Aug 19 Javascript
JS去除数组重复值的五种不同方法
Sep 06 Javascript
Bootstrap Table使用整理(五)之分页组合查询
Jun 09 Javascript
bootstrap paginator分页前后台用法示例
Jun 17 Javascript
详解如何在angular2中获取节点
Nov 23 Javascript
关于Vue单页面骨架屏实践记录
Dec 13 Javascript
jQuery仿移动端支付宝键盘的实现代码
Aug 15 jQuery
mpvue项目中使用第三方UI组件库的方法
Sep 30 Javascript
IE9 elementUI文件上传的问题解决
Oct 17 Javascript
JS删除对象中某一属性案例详解
Sep 08 Javascript
微信小程序实现首页弹出广告
Dec 03 Javascript
vue2使用keep-alive缓存多层列表页的方法
Sep 21 #Javascript
使用ng-packagr打包Angular的方法示例
Sep 21 #Javascript
基于vue中keep-alive缓存问题的解决方法
Sep 21 #Javascript
vue中前进刷新、后退缓存用户浏览数据和浏览位置的实例讲解
Sep 21 #Javascript
vue单页面应用打开新窗口显示跳转页面的实例
Sep 21 #Javascript
详解Vue改变数组中对象的属性不重新渲染View的解决方案
Sep 21 #Javascript
默认浏览器设置及vue自动打开页面的方法
Sep 21 #Javascript
You might like
PHP实现支持GET,POST,Multipart/form-data的HTTP请求类
2014/09/24 PHP
PHP微信网页授权的配置文件操作分析
2019/05/29 PHP
php设计模式之正面模式实例分析【星际争霸游戏案例】
2020/03/24 PHP
Jquery加载时从后台读取数据绑定到dropdownList实例
2013/06/09 Javascript
jquery入门必备的基本认识及实例(整理)
2013/06/24 Javascript
jquery 通过name快速取值示例
2014/01/24 Javascript
js清空表单数据的两种方式(遍历+reset)
2014/07/18 Javascript
JavaScript实现在数组中查找不同顺序排列的字符串
2014/09/26 Javascript
jquery实现动静态条形统计图
2015/08/17 Javascript
JavaScript 对象字面量讲解
2016/06/06 Javascript
Bootstrap3 内联单选和多选框
2016/12/29 Javascript
学习使用Bootstrap页面排版样式
2017/05/11 Javascript
详解Vue开发微信H5微信分享签名失败问题解决方案
2018/08/09 Javascript
详解Node.js中path模块的resolve()和join()方法的区别
2018/10/29 Javascript
新版小程序登录授权的方法
2018/12/12 Javascript
three.js实现炫酷的全景3D重力感应
2018/12/30 Javascript
[00:33]DOTA2上海特级锦标赛 CDEC战队宣传片
2016/03/04 DOTA
python gensim使用word2vec词向量处理中文语料的方法
2019/07/05 Python
简单了解Django ContentType内置组件
2019/07/23 Python
使用python制作游戏下载进度条的代码(程序说明见注释)
2019/10/24 Python
在主流系统之上安装Pygame的方法
2020/05/20 Python
python中可以声明变量类型吗
2020/06/18 Python
德国宠物用品、宠物食品及水族馆网上商店:ZooRoyal
2017/07/09 全球购物
天猫国际进口超市直营:官方直采,一站购齐
2017/12/11 全球购物
如何打开WebSphere远程debug
2014/10/10 面试题
网上开店必备创业计划书
2014/01/26 职场文书
中华美德颂演讲稿
2014/05/20 职场文书
专业技术人员年度考核评语
2014/12/31 职场文书
2015驻村干部工作总结
2015/04/07 职场文书
放假通知范文
2015/04/14 职场文书
村党总支部公开承诺书2016
2016/03/25 职场文书
redis连接被拒绝的解决方案
2021/04/12 Redis
python保存大型 .mat 数据文件报错超出 IO 限制的操作
2021/05/10 Python
一看就懂的MySQL的聚簇索引及聚簇索引是如何长高的
2021/05/25 MySQL
Vue3.0写自定义指令的简单步骤记录
2021/06/27 Vue.js
为什么MySQL 删除表数据 磁盘空间还一直被占用
2021/10/16 MySQL