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 相关文章推荐
ASP小贴士/ASP Tips javascript tips可以当桌面
Dec 10 Javascript
Jquery实现弹出层分享微博插件具备动画效果
Apr 03 Javascript
javascript创建对象、对象继承的实用方式详解
Mar 08 Javascript
动态加载js、css的实例代码
May 26 Javascript
JS经典正则表达式笔试题汇总
Dec 15 Javascript
jQuery接受后台传递的List的实例详解
Aug 02 jQuery
prototype.js简单实现ajax功能示例
Oct 18 Javascript
ES6中的迭代器、Generator函数及Generator函数的异步操作方法
May 12 Javascript
微信小程序入口场景的问题集合与相关解决方法
Jun 26 Javascript
vue ssr+koa2构建服务端渲染的示例代码
Mar 23 Javascript
vue实现循环滚动列表
Jun 30 Javascript
react中useState使用:如何实现在当前表格直接更改数据
Aug 05 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
在DC的漫画和电影中,蝙蝠侠的宿敌,小丑的真名是什么?
2020/04/09 欧美动漫
php事务处理实例详解
2014/07/11 PHP
javascript+php实现根据用户时区显示当地时间的方法
2015/03/11 PHP
php实现删除空目录的方法
2015/03/16 PHP
PHP 返回数组后处理方法(开户成功后弹窗提示)
2017/07/03 PHP
JS运动基础框架实例分析
2015/03/03 Javascript
jQuery实现图片轮播特效代码分享
2015/09/15 Javascript
JavaScript中获取时间的函数集
2016/08/16 Javascript
js拖拽功能实现代码解析
2016/11/28 Javascript
nodejs个人博客开发第三步 载入页面
2017/04/12 NodeJs
JavaScript手风琴页面制作
2017/05/17 Javascript
基于 Vue.js 之 iView UI 框架非工程化实践记录(推荐)
2017/11/21 Javascript
微信小程序ajax实现请求服务器数据及模版遍历数据功能示例
2017/12/15 Javascript
AngularJS 应用模块化的使用
2018/04/04 Javascript
详解react-redux插件入门
2018/04/19 Javascript
JS对象属性的检测与获取操作实例分析
2020/03/17 Javascript
解决ant Design中this.props.form.validateFields未执行的问题
2020/10/27 Javascript
使用Python中PDB模块中的命令来调试Python代码的教程
2015/03/30 Python
python实现查找两个字符串中相同字符并输出的方法
2015/07/11 Python
python PyTorch参数初始化和Finetune
2018/02/11 Python
flask框架使用orm连接数据库的方法示例
2018/07/16 Python
CentOS下Python3的安装及创建虚拟环境的方法
2018/11/28 Python
Python 虚拟空间的使用代码详解
2019/06/10 Python
python图的深度优先和广度优先算法实例分析
2019/10/26 Python
keras做CNN的训练误差loss的下降操作
2020/06/22 Python
波兰品牌内衣及泳装网上商店:Astratex.pl
2017/02/03 全球购物
自动化专业职业生涯规划书范文
2014/01/16 职场文书
运动会通讯稿400字
2014/01/28 职场文书
业务部主管岗位职责
2014/01/29 职场文书
授权委托书格式模板
2014/04/03 职场文书
应届生找工作求职信
2014/06/24 职场文书
意外伤害赔偿协议书范本
2014/09/28 职场文书
会议新闻稿
2015/07/17 职场文书
2017新年晚会开幕词
2016/03/03 职场文书
使用nginx配置访问wgcloud的方法
2021/06/26 Servers
Python 文字识别
2022/05/11 Python