【axios】对axios二次封装(简单向)

990 阅读5分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

axios文档地址

www.npmjs.com/package/axi…

本文只是对axios进行简单的一些封装和配置,具体的一些细节请移步axios的文档查询!

下面我们就开始进行我们的封装!

最终实现效果

  1. 在app.js中配置接口(或者可将api.js根据业务进行更细致的划分,后用esm引入拼装)
//api.js
import qs from 'qs'
import base from './base.js'
import serve from './serve.js'
export default {
    // post表单请求
    getData1(params) {
        return server.post(`${base.serve1}/xxxx`, qs.stringify(params))
    },
    // post json请求
    getData2(params) {
        return server.post(`${base.serve2}/xxxx`, params)
    },
    // get 请求
    getData2(params) {
        return server.get(`${base.serve3}/xxxx`, { params })
    },
}
  1. 在页面中使用
//index.vue
// vue2
methods:{
    async getData(){
        this.loading = true
        const res = await this.$api.getData1(this.data)
        this.loading = false
        if(res){
            // todo
        }
    }
}

// index.vue
// vue3
import { getData1 } from './api.js'
async setup(){
    const { proxy } = getCurrentInstance()
    const res = await getData1()
    if(res){
        // todo
    }
}

axios对象的创建

创建 axios 对象,添加基本配置

// serve.js
import axios from 'axios'

const config = {
  timeout: 150000
}

const serve = axios.create(config)

这里不对 config.baseUrl 做配置,是因为有些具体的业务可能会调用不同的服务接口,为了更好的维护不同的服务接口,我们在 base.js 文件中做更细致的配置。

创建 base.js 地址文件

// base.js
const base = {}
// 这里可用在配置文件中修改环境变量
const env = process.env.NODE_ENV
switch(env){
    case 'development':
        base.serve1 = '/development-api1'
        base.serve2 = '/development-api2'
        break
    case 'text':
        base.serve1 = '/text-api1'
        base.serve2 = '/text-api2'
        break
    case 'production':
        base.serve1 = '/production-api1'
        base.serve2 = '/production-api2'
        break
}
export default base

在这里不把 url地址 写到配置文件中,是为了在开发时方便切换不同的地址

url地址 写在配置文件中,如果需要切换 url地址 ,那么修改配置文件之后就需要重启服务,url才会生效

当有些业务要跟A同事联调,有些业务要跟B同事联调的时候,频繁重启服务就会浪费大量的时间

axios拦截器配置

关于拦截器, axios 的官方文档是这么描述的

You can intercept requests or responses before they are handled by then or catch.

意思就是,拦截器可以让我们在 then 或者 catch 处理之前,执行相关的一些拦截操作

拦截器具体分两种类型:

  • 请求拦截 axios.interceptors.request
  • 响应拦截 axios.interceptors.response

以下是官方文档的使用demo

// serve.js
// 添加一个请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config
  }, function (error) {
    // 处理请求错误
    return Promise.reject(error)
  })

// 添加一个响应拦截器
axios.interceptors.response.use(function (response) {
    // 在2xx范围内的任何状态码都会触发此函数
    // 对响应数据做些什么
    return response
  }, function (error) {
    // 任何超出2xx范围的状态代码都会触发此函数
    // 处理响应错误
    return Promise.reject(error)
  })

请求拦截

HTTP是一个无状态的协议,所以我们在与后端进行数据交互时,会添加一个token字段(或者其他身份标识的字段)来进行数据校验

此时我们就可以在请求拦截的时候,为http请求添加token

// serve.js
import message from 'ui/message'
// 请求拦截,serve是axios创建的实例
serve.interceptors.request.use(
  config => {
    // 每次请求携带token
    const token = getToken()
    config.headers.Authorization = token
    return config
  },
  error => message(error)
)

在请求拦截添加token之后,我们所有通过 serve 发送的 http 请求都会携带token

这里有的后端会习惯把token放在请求体里,我们也可用在请求拦截里进行处理

config.data 就是我们发送的数据,可以判断 config.data 的数据类型

根据不同的数据类型为config.data 添加token

响应拦截

在和后端进行数据通信是,一般接口都会约定一个通用的返回结构体以及通用的状态码

这个时候我们就可以在响应拦截里进行通用的代码处理

// serve.js
import { loginOut } from './utils'
// 响应拦截器
serve.interceptors.response.use(
    response => {
         /** 假设通用结构体如下
         {
            code:'1001',
            msg:'success',
            data:{
                // 返回的数据
            }
         } **/
         
         if(response.data.code === '1001') return response
         // 假设登录超时的code是 400
         if(response.data.code === '400'){
             // 做退出登录处理
             loginOut()
         }
         // 如果响应失败,不返回任何数据
    },
    error => message(error)
)

以上就是 serve.js 文件中的基本处理,以下是 serve.js 文件的完整版

// serve.js
import { loginOut } from './utils'
import axios from 'axios'

const config = {
  timeout: 150000
}

const serve = axios.create(config)

// 请求拦截器
serve.interceptors.request.use(
  config => {
    // 每次请求携带token
    const token = getToken()
    config.headers.Authorization = token
    return config
  },
  error => message(error)
)

// 响应拦截器
serve.interceptors.response.use(
    response => {
         /** 假设通用结构体如下
         {
            code:'1001',
            msg:'success',
            data:{
                // 返回的数据
            }
         } **/
         
         if(response.data.code === '1001') return response
         // 假设登录超时的code是 400
         if(response.data.code === '400'){
             // 做退出登录处理
             loginOut()
         }
         // 如果响应失败,不返回任何数据
    },
    error => message(error)
)

export default serve

接口添加配置

上文我们完整地配置了 axios 的实例对象,接下来我们利用这个实例对象来添加我们要联调的接口

// api.js
import qs from 'qs'
import base from './base.js'
import serve from './serve.js'
export default {
    // post表单请求
    getData1(params) {
        return server.post(`${base.serve1}/xxxx`, qs.stringify(params))
    },
    // post json请求
    getData2(params) {
        return server.post(`${base.serve2}/xxxx`, params)
    },
    // get 请求
    getData2(params) {
        return server.get(`${base.serve3}/xxxx`, { params })
    },
    // 继续添加你的接口
    // todo
}

这里的 api.js 文件就是我们接口总的配置文件,或者你也可以根据业务模块来把api.js进行拆分

最后在 api.js 文件中汇总暴露出去即可,如下

// api.js
import orderApi from './orderApi.js'
import userApi from './userApi.js'
export default {
    ...orderApi,
    ...userApi
}

全局挂载

在这里我们为了达到 this.$api.xxx 的使用效果,我们可用将 api.js 文件暴露出来的对象

挂载到vue实例上,这样就可以直接使用

// vue2
// main.js
import Vue from 'vue'
import api from './api.js'

Vue.prototype.$api = api

注意:以上方式只适用于vue2的开发,在 vue3setup 中已经没有 this ,如果一定要在 setup 中通过原型链去访问 $api, vue内部有一个方法可以获取实例,然后通过实例挂载 $api

// main.js
import { createApp } from 'vue'
import api from './api.js'

const app = createApp(App)
app.config.globalProperties.$api = api

以下是在vue文件中使用(不推荐)

// order.vue
import { getCurrentInstance } from 'vue'
async setup(){
    const { proxy } = getCurrentInstance()
    const res = await proxy.$api.xxx()
    if(res){
        // todo
    }
}

getCurrentInstance方法是vue内部的api,在vue的文档是没有标注的,如果要在 vue3 中更加规范地编码,可用把 api.js 这个文件进行修改

// api.js
export const getData1 = (params) => {
    return server.post(`${base.serve1}/xxxx`, qs.stringify(params))
},

export const getData2 = (params) => {
    return server.post(`${base.serve2}/xxxx`, params)
},

export const getData2 = (params) => {
    return server.get(`${base.serve3}/xxxx`, { params })
},

修改完后我们在vue文件中使用

// order.vue
import { getData1 } from './api.js'
async setup(){
    const { proxy } = getCurrentInstance()
    const res = await getData1()
    if(res){
        // todo
    }
}

结语

以上就是对 axios 进行简单封装的全过程,axios 的文档还提供了很多可配置的选项,比如覆盖默认配置、接口取消等等,这里就不展开描述,有需求的可以移步官方文档进行参考和配置。