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 相关文章推荐
写的htc的数据表格
Jan 20 Javascript
2种jQuery 实现刮刮卡效果
Feb 01 Javascript
使用jQuery+EasyUI实现CheckBoxTree的级联选中特效
Dec 06 Javascript
iOS和Android用同一个二维码实现跳转下载链接的方法
Sep 28 Javascript
touch.js 拖动、缩放、旋转 (鼠标手势)功能代码
Feb 04 Javascript
vue实现一个炫酷的日历组件
Oct 08 Javascript
详解javascript replace高级用法
Feb 17 Javascript
浅谈Node 异步IO和事件循环
May 05 Javascript
vue 实现购物车总价计算
Nov 06 Javascript
jQuery实现的移动端图片缩放功能组件示例
May 01 jQuery
vue项目使用$router.go(-1)返回时刷新原来的界面操作
Jul 26 Javascript
vue祖孙组件之间的数据传递案例
Dec 07 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中对用户身份认证实现两种方法
2011/06/04 PHP
使用HMAC-SHA1签名方法详解
2013/06/26 PHP
win7下memCache的安装过程(具体操作步骤)
2013/06/28 PHP
PHP类和对象相关系统函数与运算符小结
2016/09/28 PHP
完美解决thinkphp唯一索引重复时出错的问题
2017/03/31 PHP
第一个JavaScript入门基础 document.write输出
2010/02/22 Javascript
ajax异步刷新实现更新数据库
2012/12/03 Javascript
JS实现动态给图片添加边框的方法
2015/04/01 Javascript
Javascript页面跳转常见实现方式汇总
2015/11/28 Javascript
JavaScript使用DeviceOne开发实战(二) 生成调试安装包
2015/12/01 Javascript
AngularJS自动表单验证
2016/02/01 Javascript
BootStrap轮播HTML代码(推荐)
2016/12/10 Javascript
JavaScript自动点击链接 防止绕过浏览器访问的方法
2017/01/19 Javascript
Node+Express+MongoDB实现登录注册功能实例
2017/04/23 Javascript
一个可复用的vue分页组件
2017/05/15 Javascript
weex slider实现滑动底部导航功能
2017/08/28 Javascript
vue系列之动态路由详解【原创】
2017/09/10 Javascript
jQuery使用bind函数实现绑定多个事件的方法
2017/10/11 jQuery
浅谈super-vuex使用体验
2018/06/25 Javascript
一篇文章弄懂javascript中的执行栈与执行上下文
2019/08/09 Javascript
JavaScript中0、空字符串、'0'是true还是false的知识点分享
2019/09/16 Javascript
详细分析vue表单数据的绑定
2020/07/20 Javascript
js利用拖放实现添加删除
2020/08/27 Javascript
Python使用BeautifulSoup库解析HTML基本使用教程
2016/03/31 Python
Windows 7下Python Web环境搭建图文教程
2018/03/20 Python
python实现对服务器脚本敏感信息的加密解密功能
2019/08/13 Python
python连接PostgreSQL过程解析
2020/02/09 Python
Python下载网易云歌单歌曲的示例代码
2020/08/12 Python
仓库管理员岗位职责
2014/03/19 职场文书
庆六一文艺汇演活动方案
2014/08/26 职场文书
中队活动总结
2014/08/27 职场文书
2014年学校党建工作汇报材料
2014/11/02 职场文书
2014年管理工作总结
2014/11/22 职场文书
2015年入党积极分子评语
2015/03/26 职场文书
行政人事主管岗位职责
2015/04/11 职场文书
服务器间如何实现文件共享
2022/05/20 Servers