从实际项目出发,优雅的使用Axios及二次封装

132 阅读4分钟

Axios 是一个基于promise 的网络请求库,可以用于浏览器node.js

在浏览器中创建 XMLHttpRequests。

在 node.js 中创建 http 请求。

特性

  • 支持 Promise 请求
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持XSRF

安装

使用 npm / cnpm/ yarn / pnpm 安装

$ npm install axios
$ cnpm install axios 
$ yarn add axios
$ pnpm install axios

前言

Axios 封装了一系列常用的请求方法和拦截器,比如 get、post、put、delete、请求拦截器、响应拦截器等,但是在使用中往往会比较繁琐和重复性工作。因此,我们可以针对项目中的一些常用方式进行二次封装以满足通用性和扩展性。

在实际项目中的总结和思考,目前已完成实际项目的使用。

因为目前我们的数据来源方式有多种:

  1. 项目对应的后端
  2. 外接数据(其他部门或者第三方数据)
  3. 以前的项目数据

所以,我们对应的就是多地址配置和多种拦截器,之前也是按照每一种数据来源定义一个单独的请求文件,考虑到代码冗余性,我们最终将此封装拆分。

目标

  • 基本请求
  • 统一响应结果
  • 全局 message 提醒
  • 请求拦截器和响应拦截器
  • 多地址,多配置

基本请求

import axios from 'axios'

const baseURL = 'http://localhost:8081'

// 基础请求头
const baseConfig = {
  baseURL, // 地址
  timeout:12000, // 超时时间
  header:{ // 请求头
    'Content-Type':'application/json;charset=UTF-8;'
}

const instance = axios.create(baseConfig)

// 请求拦截器
instance.interceptors.request.use(
  (config) => {
    // 比如:token 处理等
    if(getToken()){
      config.header.Authorization = 'Bearer ' + getToken()
    }
    return config
  },
  (error) => {
    return error
  }
 )

// 响应拦截器
instance.interceptors.response.use(
  (response) => {
    return response
  },
  (error) => {
    // 错误处理
    return error
  }
)

instance.get(url, params, config){
  return instance.get(url, { params, ...config })
}
instance.post(url, data, config){
  return instance.post(url, data, {  ...config })
}
instance.put(url, data, config){
  return instance.put(url, data, {  ...config })
}
instance.delete(url, data, config){
  return instance.delete(url, data, {  ...config })
}

export default instance

统一响应结果

目前我们后端的框架结构为了避免浏览器报错,在返回结果包裹一层结构,就类似于下面这种:

// 我们目前的返回结构
{
  success: true,
  code: 200,
  data:{
    isSuccess:true,
    code:200,
    result:{
      // ...结果集
    }
  }
}

为了将职责划分,我们新建 response.js 文件,用来处理响应结果相关。具体如下:

// 定义基本响应结构
const response = {
  code: 200,
  success: true,
  message: '请求成功',
  data: {}
}

// 将响应体结构返回
export const createResponse = (config) => {
  return { ...response, ...config}
}

定义完成之后将响应体加到请求响应拦截器里面,对返回结果进行结构化处理。具体如下:

// ... 上面是其余的部分,只展示响应拦截器部分代码
// 这里我们手动规范一个返回结果格式(简化返回结构,具体从自己实际出发): { code: 200,, data: {}, message: 'success'}
instance.interceptors.response.use(
(response) => {
  if(200 <= response.code && response.data <= 304){
    return createResponse(response)
  }else{
    // 错误处理和 token 处理等
    return createResponse(response)
  }
},
(error) => {
  return error
}
)

全局配置 message 提醒

在使用接口发起异步请求后,在正常的操作中会用消息提示,例如: Element-Plus 中的 Message 消息提示组件,而一般这个提示信息后端的返回结果中会携带相关文字信息,我们这里做一个全局提醒配置,避免代码中重复书写类似相关的代码。具体如下:

import {ElMessage} from 'element-plus'

export const createMessage = (message = '成功', type = 'success') => {
  return ElMessage({
    message,
    type,
    grouping: true,
    showClose: true,
    center: true,
  })
}

可配置请求拦截和响应拦截

\

这里我们将上述的拦截器进行拆分,创建 interceptors.js 文件

// 请求拦截器
export const interceptorsRequest = (instance) => {
  return instance.interceptors.request.use(
    (config) => {
      // 比如:token 处理等
      if(getToken()){
        config.header.Authorization = 'Bearer ' + getToken()
      }
      return config
    },
    (error) => {
      return error
    }
  )
}

export const interceptorsRequest = (instance) => {
  // 响应拦截器
  return instance.interceptors.response.use(
    (response) => {
      return response
    },
    (error) => {
      // 错误处理
      return error
    }
  )
}

提取常用方法

// 常用的方法
class Methods {
  constructor(instance) {
    this.instance = instance
  }
  get(url, params, config) {
    return this.instance.get(url, { params, ...config })
  }
  post(url, data, config) {
    return this.instance.post(url, data, { ...config })
  }
  put(url, data, config) {
    return this.instance.put(url, data, { ...config })
  }
  delete(url, data, config) {
    return this.instance.delete(url, { data, ...config })
  }
  postForm(url, data, config) {
    const form = new FormData()
    for (const key in data) {
      if (Object.hasOwn(data, key)) {
        const value = data[key]
        form.append(key, value)
      }
    }
    return this.instance.post(url, form, { ...config })
  }
}
export default Methods

组合

至此我们的功能拆分基本完成,剩下最后一个封装axios实例,满足多地址,多拦截器配置。

import axios from 'axios'
import Methods from './methods
import { interceptorsRequest, interceptorsResponse } from './interceptors

const baseURL = 'http://localhost:8081'

// 基础请求头
const baseConfig = {
  baseURL, // 地址
  timeout:12000, // 超时时间
  header:{ // 请求头
    'Content-Type':'application/json;charset=UTF-8;'
}
class Request extends Methods{
  constructor(config,interceptors){
    super()
    this.instance = axios.create({ ...baseConfig, ...config })
    this.interceptors = {
      interceptorsRequest: interceptorsRequest,
      interceptorsResponse = interceptorsResponse,
      ...interceptors
    }
    // 请求拦截器
    this.interceptors.interceptorsRequest(this.instance)

    // 响应拦截器
    this.interceptors.interceptorsResponse(this.instance)
  }
}

export default Request

统一导出入口

import Request from './request'
import { interceptorsRequest, interceptorsResponse } from './interceptorsMock';

export const request = new Request()

// 多地址多拦截器配置,比如:放入mockjs 配置
export const mock = new Request(
  {
    baseURL: '/mock',
  },
  {
    interceptorsRequest,
    interceptorsResponse,
  },
)

export default Request

具体使用

import { mock, request } from './index'

// mock 请求
export const mockList = () => {
  export mock.get('/mock/list')
}
// 正常请求
export const reqList = () => {
  return request.get('/req/list')
}

// 返回结果
//const response = {
//  code: 200,
//  success: true,
//  message: '请求成功',
//  data: {}
//}

Github仓库地址:github.com/laobieyi/ax…

大家评论区多交流