Vue二次封装axios为插件使用详解


Posted in Javascript onMay 21, 2018

照例先贴上 axios 的 gitHub 地址

不管用什么方式获取数据,对于一个项目来说,代码一定要利于维护其次是一定要写的优美,因此加上一层封装是必要的

vuejs2.0 已经不再维护 vue-resource,vuejs2.0 已经使用了 axios,这也是为什么我会转到 axios 的主要原因,废话不多说:

基本的封装要求:

  1. 统一 url 配置
  2. 统一 api 请求
  3. request (请求)拦截器,例如:带上token等,设置请求头
  4. response (响应)拦截器,例如:统一错误处理,页面重定向等
  5. 根据需要,结合 Vuex 做全局的loading动画,或者错误处理
  6. 将 axios 封装成 Vue 插件使用

文件结构

使用 vue-cli 进行相关的封装,在 src 文件夹下:

src

  |

-- http 封装axios模块文件夹

   |

---- config.js axios的默认配置

---- api.js 二次封装axios,拦截器等

---- interface.js 请求接口文件

---- index.js 将axios封装成插件

config.js

默认配置参照 gitHub,以下只做示例:

export default {
  method: 'post',
  // 基础url前缀
  baseURL: 'https://easy-mock.com/mock/5ad75e9f41d4d65f0e935be4/example',
  // 请求头信息
  headers: {
   'Content-Type':'application/json;charset=UTF-8'
  },
  // 参数
  data: {},
  // 设置超时时间
  timeout: 10000,
  // 携带凭证
  withCredentials: false,
  // 返回数据类型
  responseType: 'json'
}

PS: 这里推荐一下一款 Mock 工具Easy Mock,以上请求地址来自该工具。以后有空会单独写一下怎么使用该工具。

api.js

import axios from 'axios' // 注意先安装哦
import config from './config.js' // 倒入默认配置
import qs from 'qs' // 序列化请求数据,视服务端的要求

export default function $axios (options) {
  return new Promise((resolve, reject) => {
    const instance = axios.create({
      baseURL: config.baseURL,
      headers: {},
      transformResponse: [function (data) {}]
    }
  )

  // request 拦截器
  instance.interceptors.request.use(
    config => {
      // Tip: 1
      // 请求开始的时候可以结合 vuex 开启全屏的 loading 动画

      // Tip: 2 
      // 带上 token , 可以结合 vuex 或者重 localStorage
      // if (store.getters.token) {
      //   config.headers['X-Token'] = getToken() // 让每个请求携带token--['X-Token']为自定义key 请根据实际情况自行修改
      // } else {
      //   // 重定向到登录页面  
      // }

      // Tip: 3
      // 根据请求方法,序列化传来的参数,根据后端需求是否序列化
      if (config.method.toLocaleLowerCase() === 'post' 
        || config.method.toLocaleLowerCase() === 'put' 
        || config.method.toLocaleLowerCase() === 'delete') {

        config.data = qs.stringify(config.data)
      }
      return config
    },
    error => {
      // 请求错误时做些事(接口错误、超时等)
      // Tip: 4
      // 关闭loadding
      console.log('request:', error) 
    
      // 1.判断请求超时
      if (error.code === 'ECONNABORTED' && error.message.indexOf('timeout') !== -1) {
        console.log('根据你设置的timeout/真的请求超时 判断请求现在超时了,你可以在这里加入超时的处理方案')
        // return service.request(originalRequest);//例如再重复请求一次
      }
      // 2.需要重定向到错误页面
      const errorInfo = error.response
      console.log(errorInfo)
      if (errorInfo) {
        // error =errorInfo.data//页面那边catch的时候就能拿到详细的错误信息,看最下边的Promise.reject
        const errorStatus = errorInfo.status; // 404 403 500 ... 等
        router.push({
          path: `/error/${errorStatus}`
        })
      }
      return Promise.reject(error) // 在调用的那边可以拿到(catch)你想返回的错误信息
    }
  )
 
  // response 拦截器
  instance.interceptors.response.use(
    response => {
      let data;
      // IE9时response.data是undefined,因此需要使用response.request.responseText(Stringify后的字符串)
      if(response.data == undefined){
        data = response.request.responseText
      } else{
        data = response.data
      }
      // 根据返回的code值来做不同的处理(和后端约定)
      switch (data.code) {
        case '':
        break;
        default:
      }
      // 若不是正确的返回code,且已经登录,就抛出错误
      // const err = new Error(data.description)

      // err.data = data
      // err.response = response

      // throw err
      return data
    },
    err => {
      if (err && err.response) {
        switch (err.response.status) {
          case 400:
          err.message = '请求错误'
          break
      
          case 401:
          err.message = '未授权,请登录'
          break
      
          case 403:
          err.message = '拒绝访问'
          break
      
          case 404:
          err.message = `请求地址出错: ${err.response.config.url}`
          break
      
          case 408:
          err.message = '请求超时'
          break
      
          case 500:
          err.message = '服务器内部错误'
          break
      
          case 501:
          err.message = '服务未实现'
          break
      
          case 502:
          err.message = '网关错误'
          break
      
          case 503:
          err.message = '服务不可用'
          break
      
          case 504:
          err.message = '网关超时'
          break
      
          case 505:
          err.message = 'HTTP版本不受支持'
          break
      
          default:
        }
      }
      console.error(err)
      // 此处我使用的是 element UI 的提示组件
      // Message.error(`ERROR: ${err}`);
      return Promise.reject(err) // 返回接口返回的错误信息
    }
  )
 
  //请求处理
  instance(options)
    .then((res) => {
      resolve(res)
      return false
    })
    .catch((error) => {
      reject(error)
    })
  })
}

interface.js

import axios from './api' // 倒入 api

/* 将所有接口统一起来便于维护
 * 如果项目很大可以将 url 独立成文件,接口分成不同的模块
 * 此处的数据依然来自 Easy Mock
 */

// 单独倒出
export const query = params => {
  return axios({
    url: '/query',
    method: 'get',
    params
  })
}
 
export const mock = params => {
  return axios({
    url: '/mock',
    method: 'get',
    params
  })
}

export const upload = data => {
  return axios({
    url: '/upload',
    method: 'post',
    data
  })
}

// 默认全部倒出
// 根绝需要进行 
export default {
  query,
  mock,
  upload
}

index.js

封装成 Vue 插件,便(提)于(高)使(B)用(格)

// 倒入所有接口
import apiList from './interface'

const install = Vue => {
  if (install.installed) 
    return;
  install.installed = true;

  Object.defineProperties(Vue.prototype, {
    // 注意哦,此处挂载在 Vue 原型的 $api 对象上
    $api: {
      get() {
        return apiList
      }
    }
  })
}

export default install

使用

到此为止,万事俱备就差用了,在 mian.js 中做如下操作:

// 倒入 http 文件夹下的 index.js
import api from './http/index'
Vue.use(api)

// 此时可以直接在 Vue 原型上调用 $api 了

总结

  1. 以上二次封装较为全面,基本完成了我们之前的需求
  2. 在错误的处理上还需要与后端协定好返回值,做具体的约定
  3. 封装回调有点多,在使用的时候也需要加上 then() 来处理结果,async & await 了解一下哟,好东西当然要藏起来,我才不会分享出来呢...

PS: IE9 不支持 Promise 哦,需要安装一个 polyfill

import 'babel-polyfill'

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

Javascript 相关文章推荐
JavaScript中的Repaint和Reflow用法详解
Jul 27 Javascript
JS函数的几种定义方式分析
Dec 17 Javascript
基于JS实现的笛卡尔乘积之商品发布
May 13 Javascript
原生js实现回复评论功能
Jan 18 Javascript
使用重写url机制实现验证码换一张功能
Aug 01 Javascript
解决angularjs前后端分离调用接口传递中文时中文乱码的问题
Aug 13 Javascript
前端防止用户重复提交js实现代码示例
Sep 07 Javascript
JS求1到任意数之间的所有质数的方法详解
May 20 Javascript
在Angular中实现一个级联效果的下拉框的示例代码
May 20 Javascript
原生JS实现相邻月份日历
Oct 13 Javascript
微信小程序学习之自定义滚动弹窗
Dec 20 Javascript
vue修饰符.capture和.self的区别
Apr 22 Vue.js
详解vue的diff算法原理
May 20 #Javascript
详解使用vue-admin-template的优化历程
May 20 #Javascript
vuex进阶知识点巩固
May 20 #Javascript
简单的三步vuex入门
May 20 #Javascript
vue项目如何刷新当前页面的方法
May 18 #Javascript
原生JS实现的碰撞检测功能示例
May 18 #Javascript
JS实现json对象数组按对象属性排序操作示例
May 18 #Javascript
You might like
PHP加密解密类实例分析
2015/04/20 PHP
ThinkPHP3.2.1图片验证码实现方法
2016/08/19 PHP
PHP用函数嵌入网站访问量计数器
2017/10/27 PHP
在JavaScript中遭遇级联表达式陷阱
2007/03/08 Javascript
用正则表达式 动态创建/增加css style script 兼容IE firefox
2009/03/10 Javascript
javascript attachEvent和addEventListener使用方法
2009/03/19 Javascript
JavaScript中的property和attribute介绍
2011/12/26 Javascript
jqGrid增加时--判断开始日期与结束日期(实例解析)
2013/11/08 Javascript
JavaScript 基础函数_深入剖析变量和作用域
2016/05/18 Javascript
jQuery+Ajax实现限制查询间隔的方法
2016/06/07 Javascript
Vue.js每天必学之表单控件绑定
2016/09/05 Javascript
JavaScript中关于iframe滚动条的去除和保留
2016/11/17 Javascript
jQuery实现的省市联动菜单功能示例【测试可用】
2017/01/13 Javascript
利用js判断手机是否安装某个app的多种方案
2017/02/13 Javascript
js 用于检测类数组对象的函数方法
2017/05/02 Javascript
jQuery实现页码跳转式动态数据分页
2017/12/31 jQuery
通过实例了解js函数中参数的传递
2019/06/15 Javascript
vue-cli3 取消eslint校验代码的解决办法
2020/01/16 Javascript
ES6中Set和Map用法实例详解
2020/03/02 Javascript
Python检测网站链接是否已存在
2016/04/07 Python
Python实现随机选择元素功能
2017/09/14 Python
Python-OpenCV基本操作方法详解
2018/04/02 Python
Python使用numpy模块创建数组操作示例
2018/06/20 Python
html5 canvas绘制矩形和圆形的实例代码
2016/06/16 HTML / CSS
Boutique 1美国:阿联酋奢侈时尚零售商
2017/10/16 全球购物
英国马匹装备和马术用品购物网站:Equine Superstore
2019/03/03 全球购物
学生党员思想汇报
2013/12/28 职场文书
财务专业大学生职业生涯规划范文
2013/12/30 职场文书
中文专业毕业生自荐信
2014/05/24 职场文书
跳蚤市场口号
2014/06/13 职场文书
村长党的群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
销售经理工作失职检讨书
2014/10/24 职场文书
史上最牛的辞职信
2015/02/28 职场文书
给朋友的赠语
2015/06/23 职场文书
Python代码风格与编程习惯重要吗?
2021/06/03 Python
Win11 21h2可以升级22h2吗?看看你的电脑符不符合要求
2022/07/07 数码科技