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 相关文章推荐
破解Session cookie的方法
Jul 28 Javascript
JQuery 绑定select标签的onchange事件,弹出选择的值,并实现跳转、传参
Jan 06 Javascript
jquery Moblie入门—hello world的示例代码学习
Jan 08 Javascript
web css实现整站样式互相切换
Oct 29 Javascript
jQuery操作JSON的CRUD用法实例
Feb 25 Javascript
JQuery判断checkbox是否选中及其它复选框操作方法合集
Jun 01 Javascript
JS控件bootstrap datepicker使用方法详解
Mar 25 Javascript
Vue编写多地区选择组件
Aug 21 Javascript
React组件内事件传参实现tab切换的示例代码
Jul 04 Javascript
详解Nuxt.js部署及踩过的坑
Aug 07 Javascript
IE浏览器下JS脚本提交表单后,不能自动提示问题解决方法
Jun 04 Javascript
基于vue.js仿淘宝收货地址并设置默认地址的案例分析
Aug 20 Javascript
详解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 截取字符串专题集合
2010/08/19 PHP
PHP+MySQL投票系统的设计和实现分享
2012/09/23 PHP
PHP ignore_user_abort函数详细介绍和使用实例
2014/07/15 PHP
PHP查找数值数组中不重复最大和最小的10个数的方法
2015/04/20 PHP
php获取当前月与上个月月初及月末时间戳的方法
2016/12/05 PHP
PHP实现数据库统计时间戳按天分组输出数据的方法
2017/10/10 PHP
PHP使用Redis长连接的方法详解
2018/02/12 PHP
PHP+MySQL实现模糊查询员工信息功能示例
2018/06/01 PHP
laravel框架中路由设置,路由参数和路由命名实例分析
2019/11/23 PHP
javascrip关于继承的小例子
2013/05/10 Javascript
简单几行JS Code实现IE邮件转发新浪微博
2013/07/03 Javascript
JavaScript自定义方法实现trim()、Ltrim()、Rtrim()的功能
2013/11/03 Javascript
jQuery实现从身份证号中获取出生日期和性别的方法分析
2016/02/25 Javascript
微信小程序实现流程进度的图样式功能
2018/01/16 Javascript
vue中设置height:100%无效的问题及解决方法
2018/07/27 Javascript
vue 路由子组件created和mounted不起作用的解决方法
2019/11/05 Javascript
vue实现列表滚动的过渡动画
2020/06/29 Javascript
antd table按表格里的日期去排序操作
2020/11/17 Javascript
[15:35]教你分分钟做大人:天怒法师
2014/10/30 DOTA
python3使用tkinter实现ui界面简单实例
2014/01/10 Python
Python multiprocessing.Manager介绍和实例(进程间共享数据)
2014/11/21 Python
快速入手Python字符编码
2016/08/03 Python
Python实现删除文件中含“指定内容”的行示例
2017/06/09 Python
Python实现批量压缩图片
2018/01/25 Python
详解Django中类视图使用装饰器的方式
2018/08/12 Python
Python openpyxl读取单元格字体颜色过程解析
2019/09/03 Python
python3中关于excel追加写入格式被覆盖问题(实例代码)
2020/01/10 Python
Python 爬取淘宝商品信息栏目的实现
2021/02/06 Python
CSS3支持IE6, 7, and 8的边框border属性
2012/12/28 HTML / CSS
MAC Cosmetics巴西官方网站:M·A·C彩妆
2019/04/18 全球购物
JYSK加拿大:购买家具、床垫、家居装饰等
2020/02/14 全球购物
美丽家庭事迹材料
2014/05/03 职场文书
车辆委托书范本
2014/10/05 职场文书
2019年“我为祖国点赞”演讲稿(3篇)
2019/09/26 职场文书
Python激活Anaconda环境变量的详细步骤
2021/06/08 Python
一行Python命令实现批量加水印
2022/04/07 Python