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 相关文章推荐
jQuery链式操作如何实现以及为什么要用链式操作
Jan 17 Javascript
jquery选择器之内容过滤选择器详解
Jan 27 Javascript
js实现表单Radio切换效果的方法
Aug 17 Javascript
原生js页面滚动延迟加载图片
Dec 20 Javascript
jQuery实现侧浮窗与中浮窗切换效果的方法
Sep 05 Javascript
vue.js学习笔记之绑定style样式和class列表
Oct 31 Javascript
最细致的vue.js基础语法 值得收藏!
Nov 03 Javascript
jquery 禁止鼠标右键并监听右键事件
Apr 27 jQuery
JavaScript瀑布流布局实现代码
May 06 Javascript
AngularJS $http post 传递参数数据的方法
Oct 09 Javascript
微信小程序上线发布流程图文详解
May 06 Javascript
vue input标签通用指令校验的实现
Nov 05 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
BBS(php &amp; mysql)完整版(五)
2006/10/09 PHP
PHP实现Google plus的好友拖拽分组效果
2016/10/21 PHP
详解PHP编码转换函数应用技巧
2016/10/22 PHP
PHP构造二叉树算法示例
2017/06/21 PHP
PHP设计模式之工厂模式定义与用法详解
2018/04/03 PHP
Laravel事件监听器用法实例分析
2019/03/12 PHP
js实现动态改变字体大小代码
2014/01/02 Javascript
ajax如何实现页面局部跳转与结果返回
2015/08/24 Javascript
jquery获取文档高度和窗口高度汇总
2016/01/25 Javascript
jQuery简单实现中间浮窗效果
2016/09/04 Javascript
AngularJs ng-change事件/指令的用法小结
2017/11/01 Javascript
基于滚动条位置判断的简单实例
2017/12/14 Javascript
vue项目中使用eslint+prettier规范与检查代码的方法
2020/01/16 Javascript
JavaScript进阶(一)变量声明提升实例分析
2020/05/09 Javascript
基于python的七种经典排序算法(推荐)
2016/12/08 Python
Python实现脚本锁功能(同时只能执行一个脚本)
2017/05/10 Python
python线程池(threadpool)模块使用笔记详解
2017/11/17 Python
Python+selenium实现自动循环扔QQ邮箱漂流瓶
2018/05/29 Python
python迭代dict的key和value的方法
2018/07/06 Python
python版本单链表实现代码
2018/09/28 Python
Python读取Pickle文件信息并计算与当前时间间隔的方法分析
2019/01/30 Python
python获取点击的坐标画图形的方法
2019/07/09 Python
Django 多表关联 存储 使用方法详解 ManyToManyField save
2019/08/09 Python
python自动识别文本编码格式代码
2019/12/26 Python
在tensorflow中设置保存checkpoint的最大数量实例
2020/01/21 Python
Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释
2020/01/25 Python
python打包生成so文件的实现
2020/10/30 Python
浅谈HTML5中dialog元素尝鲜
2018/10/15 HTML / CSS
吃透移动端 Html5 响应式布局
2019/12/16 HTML / CSS
惠普新加坡官方商店:HP Singapore
2020/04/17 全球购物
求职信范文英文版
2014/01/05 职场文书
致100米运动员广播稿
2014/02/14 职场文书
分公司负责人任命书
2014/06/04 职场文书
安全伴我行演讲稿
2014/09/04 职场文书
入党积极分子群众意见
2015/06/01 职场文书
2016年圣诞节义工活动总结
2016/04/01 职场文书