问题点

在实际开发 项目 过程中 可以发现 我们每个人都要去写API接口的定义 不断的拷贝代码 可以直观地看出来 API接口大部分都是相同的 只有接口的地址是不同的。

这部分重复的代码量比较多,而且还存在一个问题就是 请求来的数据是被一个data包装起来的 每次要使用数据的时候都会要将data内的内容解构出来。

这种做法虽然浪费不了太多时间 ,但其实也是积少成多的 重复的东西一而再再而三的出现 合起来浪费的时间也是很长的。

原因

根本原因在于 我们大家写接口的时候都是分开来处理的 因为不可能说是一口气把所有的接口都给写上 肯定是 需要哪个接口就去写哪个接口的定义。

并且在使用接口的时候 都需要解构出data的内容 。但就我个人而言,一直感觉 不就是一个解构 来回写 费不了多长时间 所以一直就没有去做这方面的封装.

解决

1. 原有的请求模式

  1. 1.1.1. 问题点

业务中经常需要调用请求 但对于请求的处理 可以说是比较繁琐 基本每个请求都要这样写

现业务中请求的代码 折叠源码

// 先定义一个请求函数
export const sssss = (data) => {
    return axios.request({
        url: 'sssss',
        method: 'post',
        data
    });
};
// 然后回到页面文件 将请求 引入并使用
import {sssss} '@api/xxxxx'
 
 
sssss({ ssss: sss.sss, ssss: 'ssss' })
    .then((res) => {
         const { status, result } = res.data; if (status === 200) { // 省略业务代码 }
     })
     .catch((err) => {
        console.log(err);
    })

可以看到这里的数据其实是在res.data里的 这里才是前端所需要的数据 不知道是前端层包装的还是后端层包装的

我们经常需要要在请求内 使用es6的解构 将真正的数据解构出来使用 这一步我个人认为挺麻烦的 所以去查找 为什么会出现这种情况 经过多方询问 并且亲自实践 发现后端返回的数据格式是干净的

通过图片可以看到 后端确确实实是只返回了 result status

但是 我们可以看一下前端接口result的数据

请输入图片描述

可以看到是由一个data将这个数据包装了起来 这是为什么呢?

1.1.2. 2.问题点出现的原因

由于我们的请求工具是axios 所以深入的观看了一下 axios的官方文档 看到了一个 '响应结构'

请输入图片描述

我第一眼 看到这个响应结构的时候 就在想 哎? 这个data status 是不是就是我们所在浏览器端请求看到的res数据呢?

然后 当我进入到 axios的封装文件内 可以发现 有一个响应拦截器 这个响应拦截器是做什么的呢?

我们来看官方文档 下图可以看到 响应拦截器的作用是 对相应的数据做点什么

那么是不是就是因为响应拦截器 将我们后端发来的数据进行了重新包装?

请输入图片描述

让我们 来看看 响应拦截器的代码是怎么写的

下图中我们可以看到 在响应拦截器中 第一个参数 res的数据 其实就对应了我们在上面说到的 响应结构

看代码可以看出来 很直观地看出来就是 这里 将 data(后端数据) status (服务器所返回的状态码) 从 响应结构中 解构了出来

然后 再给他们包装并return 就出现了我们在前端浏览器方面看到的 那样 返回了一个 data status

请输入图片描述

由于 不太懂后端 是怎么写的 理论上来讲 后端是可以控制服务器返回的状态码 所以并不需要在数据内伪造一个自定的状态码

这是我之前在nodejs端写的 响应 可以看到 我这里可以设置302的响应状态码

请输入图片描述

1.1.3. 3.解决方案

到这里 这个东西可以说是从根源上解决掉了他 我可以在响应拦截器内 直接返回后端的data 而不返回服务器的状态码

当然 更希望 后端能够 控制整个服务器状态码 前端就不需要改动太多业务代码

现在业务代码由于太多是从data中解构数据 如果要是直接返回后端的data 反而 会影响大批量范围的业务代码 从而适得其反

请输入图片描述

2. 改善后的请求模式

所以 想了一种折中的办法 使用函数来将请求包装一层 使其能直接返回后端返回的真实数据

基本实现代码如下

// 解决 调用请求时 每次都需要将请求内的数据解构开
// 期望直接得到请求的数据 或 错误信息
// 因后端通常 返回的数据格式是 {data:{status:200,result:{}},status:200}
// 前端一般只需要 data内的信息
const request = (url, method, data) => {
    return new Promise((resolve, reject) => {
            try {
                axios .request({ url, method, data })
                    .then((res) => {
                        const { status, result } = res.data;
                        // 状态码不是200的情况下 一般会提示一个弹窗之类的
                        // 这个弹窗可以是封装出来的一个全局弹窗
                        // 用函数式的方式调用弹窗...
                        // 此阶段还可以传入一个清洗函数 将数据清洗为方便前端使用的数据.
                        if (status === 200) resolve(result); })
                    .catch((err) => {
                        console.log(err);
                        reject(err);
                    });
                 } catch (error) {
                     console.log(error);
                    }
                });
    };

经改进之后的请求代码

// 定义一个请求函数
export const aaa = (data) => { return request('aaa', 'post', data); };
// 使用 // 省略了对状态码判断的处理 then内是直出的后端数据 aaa().then(res=>console.log(res)).catch(err=>console.log(err))

改进前后的代码对比虽然不是很明显 但是 更易维护了 并且发挥想象的话 可以通过传递配置项 来控制 是否有错误弹窗 弹窗内容 又或是传入一个函数 将数据处理

扩展
由于上面的封装改进优点并不明显 一般理想情况下 可以写一个程序 来通过基于json字段 自动创建出来接口的定义文件 减少前端 复制粘贴生成接口定义

总结

DRY 原则,DRY 的全称是 —— Don't Repeat Yourself !

指编程过程中不写重复代码,将能够公共的部分抽象出来,封装成工具类或者用抽象类来抽象公共的东西,从而降低代码的耦合性,这样不仅提高代码的灵活性、健壮性以及可读性,也方便后期的维护。

三次原则, 表示 第一次用到某个功能时,你写一个特定的解决方法;第二次又用到的时候,你拷贝上一次的代码;第三次出现的时候,你才着手"抽象化",写出通用的解决方法.

总体来说呢 就是在写代码时候 多考虑一下团队集体 尽量为团队 积累 贡献代码

遇到与往期开发 类似的功能时候 尽量花费点时间去将这个东西 抽离为方法 或 组件

也可以记录在自己的个人待办事项 待日后开发 或 与团队沟通大家一起找时间开发

遇到好的代码(比如正则 在团队内做分享 这样大家做到相同需求的时候可以直接复用

最后修改:2023 年 03 月 06 日
如果觉得我的文章对你有用,请随意赞赏