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 document.compatMode兼容性
Feb 23 Javascript
jquery实现的元素的left增加N像素 鼠标移开会慢慢的移动到原来的位置
Mar 21 Javascript
JQuery 应用 JQuery.groupTable.js
Dec 15 Javascript
JavaScript实现找出数组中最长的连续数字序列
Sep 03 Javascript
JS实现屏蔽shift,Ctrl,alt等功能键的方法
Jun 01 Javascript
AngularJS基础 ng-disabled 指令详解及简单示例
Aug 01 Javascript
浅谈jQuery中事情的动态绑定
Feb 12 Javascript
vue父子组件的数据传递示例
Mar 07 Javascript
微信小程序自定义音乐进度条的实例代码
Aug 28 Javascript
JS实现数组去重及数组内对象去重功能示例
Feb 02 Javascript
node.js微信小程序配置消息推送的实现
Feb 13 Javascript
java实现单链表增删改查的实例代码详解
Aug 30 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
完美解决在ThinkPHP控制器中命名空间的问题
2017/05/05 PHP
浅谈PHP实现大流量下抢购方案
2017/12/15 PHP
thinkPHP3.2.2框架行为扩展及demo示例
2018/06/19 PHP
JS 用6N±1法求素数 实例教程
2009/10/20 Javascript
file模式访问网页时iframe高度自适应解决方案
2013/01/16 Javascript
深入探寻seajs的模块化与加载方式
2015/04/14 Javascript
jQuery实现的超简单点赞效果实例分析
2015/12/31 Javascript
JavaScript将DOM事件处理程序封装为event.js 出现的低级错误问题
2016/08/03 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
2016/11/18 Javascript
vue swipe自定义组件实现轮播效果
2019/07/03 Javascript
js面向对象之实现淘宝放大镜
2020/01/15 Javascript
Node.js API详解之 Error模块用法实例分析
2020/05/14 Javascript
JavaScript组合模式---引入案例分析
2020/05/23 Javascript
[16:21]教你分分钟做大人:圣堂刺客
2014/12/03 DOTA
phpsir 开发 一个检测百度关键字网站排名的python 程序
2009/09/17 Python
Python实现Const详解
2015/01/27 Python
浅谈python中对于json写入txt文件的编码问题
2018/06/07 Python
详解Django中间件的5种自定义方法
2018/07/26 Python
使用Python做定时任务及时了解互联网动态
2019/05/15 Python
Python中调用其他程序的方式详解
2019/08/06 Python
使用虚拟环境打包python为exe 文件的方法
2019/08/29 Python
关于初始种子自动选取的区域生长实例(python+opencv)
2020/01/16 Python
美国一家著名的儿童鞋制造商:Stride Rite
2017/01/02 全球购物
创业资金计划书
2014/02/06 职场文书
联片教研活动总结
2014/07/01 职场文书
公安派出所所长四风问题个人对照检查材料
2014/10/04 职场文书
优秀工作者事迹材料
2014/12/26 职场文书
泰山导游词
2015/02/02 职场文书
幼儿园辞职信范文
2015/02/27 职场文书
采购内勤岗位职责
2015/04/13 职场文书
2015年乡镇卫生院妇幼保健工作总结
2015/05/19 职场文书
2016高中社会实践心得体会范文
2016/01/14 职场文书
Laravel中获取IP的真实地理位置
2021/04/01 PHP
python实现自定义日志的具体方法
2021/05/28 Python
CSS控制继承中的height能变为可继承吗
2022/06/10 HTML / CSS
Python中tqdm的使用和例子
2022/09/23 Python