如何优化代码中api的请求结构

(注:下面以vue项目为例子)

一. 一般项目中api的调用方式

1. 目录结构

|── src
|── |── utils (工具方法文件夹)
|── |── |── http.js (封装的请求方法)
|── |── views (页面文件夹)
|── |── |── device (可以理解为一级菜单)
|── |── |── |── board(可以理解为二级菜单页面)
|── |── |── |── |── index.vue

2. 常见的api调用形式

第一步: 一般都会在http.js中封装好axios的get,post等方法,利用拦截器统一处理请求前和响应后的逻辑。
将http这个方法绑定在vue实例上,Vue.prototype.$http = http
第二步: 在上面index.vue中调用

<script>
export default {
  data () {
    return {
      data: ""
    }
  },
  methods: {
    async getData () {
    const { data } = await this.$https.get("/url/test")
    this.data = data
  }
 }
</script>

3. 问题

(1) 我们传入的后端地址"/url/test",如果要继续用到,我们还是要重复写一遍 this.$https.get("/url/test");
(2) 当页面中有大量的接口调用就会出现接口地址不易管理的情况,这个能否新建一个文件统一管理?

二. 理想项目中的api组织结构(优化1)

1. 目录结构

我们应该有一个api文件夹,存放当前对应模块的接口
board.js 中是这样定义的

import { http } form '@/utils/http.js'
export default {
  getBoardData () {
    return http.get("/url/test")
  }
}

|── src
|── |── utils
|── |── |── http.js
|── |── views
|── |── |── device (可以理解为一级菜单)
|── |── |── |── board(可以理解为二级菜单页面)
|── |── |── |── |── index.vue
|── |── api
|── |── |── common (存放公共的方法)
|── |── |── |── index.js
|── |── |── device (一级菜单名)
|── |── |── |── board.js(二级菜单页面名字)
|── |── |── index.js

2. 调用

在 board的模块下的index.vue中使用

<script>
import boardApi from "@/api/device/board.js"
export default {
  data () {
    return {
      data: ""
    }
  },
  methods: {
    async getData () {
    const { data } = await boardApi.getBoardData()
    this.data = datad
  }
 }
<script>

3. 问题

(1) 每次都要import, 能不能用一个全局变量去加载这些接口文件,$service.getData()的形式

三 . 理想项目中的api组织结构(优化2)

1. webpack的require.context

通过 require.context() 函数来创建自己的 context。
可以给这个函数传入三个参数:一个要搜索的目录,一个标记表示是否还搜索其子目录, 以及一个匹配文件的正则表达式。

// 找出当前目录下包括子目录所有以.js结尾的文件
const files = require.context("./",true, "\.js$") 

所以我们可以利用webpack的require.context得到我们的文件结构

2. 在api文件夹的index.js

|── src
|── |── utils
|── |── |── http.js
|── |── views
|── |── |── device (可以理解为一级菜单)
|── |── |── |── board(可以理解为二级菜单页面)
|── |── |── |── |── index.vue
|── |── api
|── |── |── common (存放公共的方法)
|── |── |── |── index.js
|── |── |── device (一级菜单名)
|── |── |── |── board.js(二级菜单页面名字)
|── |── |── index.js

// api文件的index.js
const files = require.context('./', true, /\.js$/)

const commonApis = {}

files.keys().forEach(key => { //require.context的 keys() 返回一个文件路径匹配数组
 
  if (key === './index.js') {
    return false
  }
  const arr = key.match(/\.\/(.*)\/(.*).js)
  /**
  * commonApis的结构
  * {
  *   device: {
  *     getBoardData () {}
  *   }
  *
  * }
  */
  commonApis[arr[1]] = { ...commonApis[arr[1]], ...files(key).default }
})
export default commonApis

3.调用

  //commonApis的结构
  {
   device: { // 一级菜单名
      getBoardData () {}
    }
  }

以上我们得到了一个commonApis的对象,我们得把它绑定在一个变量上,比如$service
所以需要在 vue.config.js 定义

const webpack = require('webpack')
const path = require('path')
function resolve (dir) {
  return path.join(__dirname, dir)
}

module.exports = {
  // 调整 webpack 配置(放置plugins等)
  configureWebpack: {
    resolve: {
      alias: { // 给路径起别名
        service: resolve('src/api/index.js')
      }
    },
    plugins: [
      new webpack.ProvidePlugin({ // 自动加载模块的插件
        $service: ['service', 'default'],
      })
    ]
  }
}

这样就可以在board中index.vue中这样调用

<script>
export default {
  data () {
    return {
      data: ""
    }
  },
  methods: {
    async getData () {
    const { data } = await $service.device.getBoardData()
    this.data = data
  }
 }
</script>
原文地址:https://www.cnblogs.com/listenMao/p/15521764.html