优化封装 axios 的代码,确保网络请求逻辑更加简洁、易维护,并且在性能和可扩展性上有所提升

 优化后的目标包括:

  1. 签名的生成:抽离签名生成逻辑,使得代码更加简洁、复用性更高。
  2. 请求去重:减少重复请求,提高性能,避免不必要的请求发送。
  3. 请求配置与错误处理:优化请求配置和错误处理,使代码更易于理解和维护。


准备工作:目前代码基于 vue + element-plus + axios + md5 + dayjs + crypto-js(注:本项目的加密方式是hmac-sha256 加密传输)

    "axios": "^1.6.8",
    "crypto-js": "^4.2.0",
    "dayjs": "^1.11.10",
    "element-plus": "2.7.0",
    "js-cookie": "^3.0.5",
    "js-md5": "^0.8.3",
    "mitt": "^3.0.1",
    "nprogress": "^0.2.0",
    "pinia": "^2.1.7",
    "pinia-plugin-persistedstate": "^4.2.0",
    "readify-manager": "file:",
    "vue": "^3.4.21",
    "vue-error-boundary": "^2.0.3",
    "vue-router": "^4.3.0"

1. 优化后的 api.js 更简洁、清晰

// api.js 部分

import { HTTP_Request } from '../axios' // 具体位置具体导入

//  付费套餐分类列表
export const getBillingCategoryList = params => {
  return HTTP_Request.get('/admin/categoryList', params)  // 具体路径具体输入
}
//  添加付费套餐分类
export const addBillingCategory = params => {
  return HTTP_Request.post('/admin/addCategory', params)
}
//  删除添加付费套餐分类
export const deleteBillingCategory = params => {
  return HTTP_Request.delete(`/admin/delCategory/${params.id}`)
}
//  更新付费套餐分类
export const updateBillingCategory = params => {
  return HTTP_Request.put('/admin/editCategory', params)
}


...

2. 封装的 axios.js 部分

// axios.js

import axios from 'axios'
import { sortObjASCII } from '@/utils'
import { Message } from '@/utils/message'
import Cookies from 'js-cookie'
import md5 from 'js-md5'
import router from '@/router'
import CryptoJS from 'crypto-js'

const CancelToken = axios.CancelToken
const pending = new Map()

// 创建实例
class HttpRequest {
  constructor (baseURL) {
    this.baseURL = baseURL
    this.timeout = 1000 * 60 * 2
    this.withCredentials = true
  }
  // 中间件
  middleRequest (options = {}) {
    const instance = axios.create()
    const config = {
      ...options,
      baseURL: this.baseURL,
      timeout: this.timeout,
      withCredentials: this.withCredentials,
      headers: {
        Authorization: 'Bearer ' + Cookies.get('token')
        // 'Content-Type': 'application/json'
      }
    }

    if (options.data instanceof FormData) {
      // 如果是文件上传,Content-Type 应该是 multipart/form-data,axios 会自动设置
      config.headers['Content-Type'] = 'multipart/form-data'
    } else {
      // 默认设置 JSON 格式
      config.headers['Content-Type'] = 'application/json'
    }

    this.setInterceptors(instance, options.url)
    return instance(config)
  }
  // GET
  get (url, params, options = {}) {
    const GET = this.middleRequest({
      method: 'get',
      url: url,
      params: params,
      ...options
    })
    return GET
  }
  // POST
  post (url, params, options = {}) {
    const POST = this.middleRequest({
      method: 'post',
      url: url,
      data: params,
      ...options
    })
    return POST
  }
  // PUT
  put (url, params, options = {}) {
    const PUT = this.middleRequest({
      method: 'put',
      url: url,
      data: params,
      ...options
    })
    return PUT
  }
  // PUT
  patch (url, params, options = {}) {
    const PATCH = this.middleRequest({
      method: 'patch',
      url: url,
      data: params,
      ...options
    })
    return PATCH
  }
  // DELETE
  delete (url, params, options = {}) {
    const DELETE = this.middleRequest({
      method: 'delete',
      url: url,
      data: params,
      ...options
    })
    return DELETE
  }
  // appid:dkFv5OrWyQhte1ZG    appsecret : d34cea92316d1da113135158bed9ca97     sign_secret:  &4F2g4Y6b4L4R1
  // 签名
  sign (config) {
    const appid = 'dkFv5OrWyQhte1ZG'
    const appsecret = 'd34cea92316d1da113135158bed9ca97'
    const Timestamp = Date.parse(new Date()).toString()
    const Url = decodeURIComponent(config.baseURL + config.url)
    const signparamsData = config.data || config.params
    let signData = { appid, appsecret, Timestamp, Url, ...signparamsData }
    signData = sortObjASCII(signData)
    let signStr = Object.entries(signData)
      .map(([key, val]) => `${key}=${val}`)
      .join('&')
    config.headers.appid = appid
    config.headers.appsecret = appsecret
    config.headers.sign_secret = md5(md5(signStr))
    config.headers.Timestamp = Timestamp
  }
  // 撤销重复请求
  changePending (config) {
    this.sign(config)
    const url = [config.method, config.url].join('&')
    config.cancelToken =
      config.cancelToken ||
      new CancelToken(cancel => {
        if (pending.has(url)) {
          pending.set(url, cancel)
        } else if (pending.has(url)) {
          const cancel = pending.get(url)
          cancel(url)
          pending.delete(url)
        }
      })
    return config
  }
  // 清空请求
  clearPending () {
    for (const [url, cancel] of this.pending) {
      cancel(url)
    }
    this.pending.clear()
  }

  // 拦截器
  setInterceptors (instance) {
    this.requestInterceptors(instance)
    this.responseInterceptors(instance)
  }
  // 请求拦截器

  requestInterceptors (instance) {
    instance.interceptors.request.use(
      config => {
        return this.changePending(config)
      },
      err => {
        return Promise.reject(err)
      }
    )
  }
  // 响应拦截器
  /**
   * code:
   * 400:请求出错
   * 401:登录失效,cookie中无Authorization字段
   * 403:请求被拒绝
   * 404:请求未找到
   * 500:服务异常
   *
   */
  responseInterceptors (instance) {
    instance.interceptors.response.use(
      response => {
        if (
          response.status >= 200 &&
          response.status < 300 &&
          response.data.code == 200
        ) {
          return Promise.resolve(response.data)
        } else {
          // The token has expired, please log in again
          if ([401].includes(response.status || response.data.code)) {
            Message.error(response.data.message)
            Cookies.remove('token')
            router.push('/login', { replace: true })
            localStorage.clear()
            sessionStorage.clear()
            return Promise.reject(response.data)
          }
          Message.error(response.data.message)
          return Promise.reject(response.data)
        }
      },
      error => {
        console.log(error)
        // The token has expired, please log in again
        if ([401].includes(error.status)) {
          Cookies.remove('token')

          router.push('/login', { replace: true })

          return Promise.reject(error.response?.data || error)
        }
        if (['ERR_NETWORK'].includes(error.code)) {
          Message.error(error.message)
          return Promise.reject(error)
        }
        return Promise.reject(error.response?.data || error)
      }
    )
  }
}

const HTTP_Request = new HttpRequest(import.meta.env.VITE_BASE_URL)

export { HTTP_Request }

3. utils/sortObjASCII.js 部分

// utils/sortObjASCII.js 部分

// 引入day.js
import dayjs from "dayjs"
import HmacSHA256 from "crypto-js/hmac-sha256";

// data type
export const getDataType = (data) => {
    return Object.prototype.toString.call(data).match(/\s(\w+)/)[1]
}

// isBlob
export const isBlob = (data) => {
    const obj = new Blob([data])
    return obj instanceof Blob ? true : false
}
// isNaN
export const isNumber = val => {
    return !isNaN(parseFloat(val)) && isFinite(val);
}
// format date
export const formatDate = (date) => {
    if (!date) return
    let formatDate = dayjs(date).format('YYYY-MM-DD HH:mm:ss')
    return formatDate
}
// format money 保留两位小数
export const formatMoney = (val, prfix = 'CA$') => {
    if (!val) return prfix + '0.00'
    let formatMoney = parseFloat(val).toFixed(2);
    return prfix + formatMoney
}

// 获取对象排序
export const sortObjASCII = (data) => {
    let sortObj = {}
    const jsonString = JSON.stringify(data);
    const obj = JSON.parse(jsonString);
    let arr = Object.keys(obj).sort()
    if (arr.length === 0) return {}
    for (let ii in arr) {
        sortObj[arr[ii]] = obj[arr[ii]]
    }
    return sortObj
}

// blob转base64
export const blobToBase64 = (blob) => {
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.onerror = reject;
        reader.readAsDataURL(blob);
    });
}

// 是否中文
export const containsChinese = (val) => {
    const chineseRegex = /[\u4e00-\u9fff]/;
    return chineseRegex.test(val);
}

// 延时函数
export const sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));

export const encryptHmacSHA256 = (data) => {
    // 密钥
    const secretKey = "fA3bX9zKp2LmTqY7";
    const hash = HmacSHA256(data, secretKey).toString();
    return hash;
  };

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值