碎碎念
看了下上次文章发布时间,2个月前。好久没更新了。技术深度方面也没有特别多的一个加深。这次来一个老生常谈的事情吧。api服务封装。这是我干前端这些年一步步慢慢优化过来的代码。
特性:
1、支持多个不同微服务(核心)
2、集中配置中心
3、简化开发流程和优化开发体验
4、解耦,可移植
一、列举下大家都是怎么封装的接口服务
我来吐槽下大家这些都会产生什么问题,我全部试过
1、增加接口拦截服务,什么重复接口防止提交
好多文章都在axios上面做文章,基于axios本身的api进行再封装。先不提缺点。本身你去拦截重复的路由最大的问题是项目越来越大之后,你一个页面两个地方用一个接口我问你怎么办?
2、防抖处理,优化业务代码,避免瞬间多次提交
这个封装的主要目的是为了我们像保存等操作按钮,避免瞬间提交两次以上。比如loading等方式并不是百分百没问题的。
但是这个因为你的防抖封装在全局,那么当一个瞬间有两个以上的api的时候,结果只有第一个api有效。别的api无法请求了。当然你愿意用class方式创建api,非要去new一个对象那就不存在这种情况了。
3、像后端一样用rest服务方式(ps:LJ)
这个我真的是觉得你们很S,我们封装的目的是为了节省代码量,不是让你增加代码量
post,get,delete全部写一个函数,你是不是闲得慌
4、好像在社区经常看见的就是这些方案
暂时先这样。
二、为什么要封装api服务?
1、让我们少写代码
为了省代码啊,大哥大姐们?我最受不了的就是那种什么都不封装,包括直接那axios直接api使用的项目了。你针对你单个业务环境还好,但是每个业务环境封装一个不闲累得慌啊。
还有,就是好多新手,老手老干的事情,就是直接怼上去。直接就是用。项目后期让你改个东西要疯,想上统一管理或者一些全局监听等等,唉……
2、业务痛点
当公司大一点之后你后端服务就不只是一个,必定是两个以上的服务。偏偏吧每个服务的返回值判断还不一定对。你非要在实际编写的时候一一判断吗?
你上手机端,pc端,小程序等等环境每次都重新封装一套?然后每次都需要为了这个服务不断更新换代?好痛苦啊。
还有一些项目需要直接就是全局loading等待接口的,单独写也是代码量啊
三、代码解析
md文件更新不太及时。见谅哈
首先是目录结构
1、config.js
这个没什么特别的主要是根据不同的微服务进行一个提前配置
2、base文件
核心是axiosAjax.js,tips.js主要是为了把提示信息全局的拿出来。很多地方都需要进行使用
代码解析
可以看到本身其实非常的简单,主要是把axios先做了一次封装,参数大家应该都懂了。这里做了一个省代码操作,加入了emelent-ui的loading处理
这里的核心目的是解耦axios,方面我在后期比如移植到小程序环境下进行使用。那么我的核心api部分就可以解放出来,非常关键的地方。
import axios from 'axios'
import { Loading } from 'element-ui'
// axios函数封装
const ajax = ({
url = '',
loading = false, // 加载拦截
baseURL = '',
data = {},
headers = { 'Content-Type': 'application/json;charset=UTF-8' }, // 头部信息处理
method = 'get',
timeout = 30 * 1000,
responseType = 'json', // 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
}) => {
// 接口全局加载提示
let loadingInstance = ''
if (loading !== false) {
loadingInstance = Loading.service({
lock: true,
text: loading !== true ? loading : '加载中……',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.5)',
})
}
const posts = ['put', 'post', 'patch'] // 使用data作为发送数据主体
return new Promise((suc, err) => {
// 预处理数据部分
method = method.toLocaleLowerCase() // 转化为小写
axios({
url: url,
baseURL: baseURL,
headers: headers,
method: method,
[posts.includes(method) ? 'data' : 'params']: data,
timeout: timeout,
responseType,
})
.then((response) => {
loadingInstance && loadingInstance.close()
suc(response)
})
.catch((e) => {
loadingInstance && loadingInstance.close()
err(e)
})
})
}
export { ajax }
3、couplingAjax.js解析
这里不贴全部代码了。说一下这里做了什么。
首先是入参部分
1、opt参数部分
比较特殊的几个参数file,isResponse,reLogin
file是比较特殊的,是因为file独立属于文件模式。因为项目的文件都需要口令校验才可以下载,那么就需要利用file参数,当文件下载模式的情况下,我们就不需要再去处理常规的业务流程了。
isResponse是因为我实际上会对代码的使用做一次优化,我们知道取返回参数的时候是需要data.data的。我这一步给省了,提前给你取好。这要又省了一点代码。但是有时候特殊情况需要完整的返回结构,根据后端的错误码或者其他字段定制定制信息。那么就需要放开该功能
reLogin很简单,接口都需要走授权口令,口令不通过需要跳转到登录页,传入false那么就不跳了
opt.error,默认为true,当接口报错的时候后端有错误信息,统一封装进行提示。可以传入false进行关闭。也可以传入字符串,把提示信息改为你要的提示信息
opt.success 和error参数同理
2、截图的中间部分
prefix = '', // 路由的前缀,这里会作为微服务的前缀拼接到每个路由前面,少写点代码
codeField = 'success', // 成功判断字段
dataField = 'data', // 快速取值字段
codeNum = true, // 成功判断值
msgField = 'message', // 提示信息或者错误信息
tipsCode = 'errorCode', // 错误码
prefix特殊一点。等下index部分就知道怎么配置使用了
4、index.js入口文件解析
这个文件就很简单了,主要是让大家看一下prefix有什么用
5、apis文件的使用,根据微服务进行划分文件夹或者文件
根据微服务划分的文件和fil参数使用情况和基本配置
6、使用
import service from '@/services'
async test() {
try {
// 正确信息
const res = await service.Nbs.ceshi({
url = '', // url地址
loading: false, //加载拦截loaing,可以传入字符串更换提示信息
baseURL: '', // 基础路径前缀
data: {}, // 不管是get还是post参数都放这里
headers: { 'Content-Type': 'application/json;charset=UTF-8' }, //头部信息处理
method: 'get', // 访问方式
timeout: 30 * 1000, // 接口超时时间
error: true, // 错误提示信息:可以传入字符串,传入字符串则不管什么提示都是该字符串提示
success: false // 成功信息提示:可以传入字符串,传入字符串则不管什么提示都是该字符串提示
})
console.log(res)
} catch (e) {
// 错误信息统一都在这里
console.log(e)
}
}
四、总结和致谢
1、总体来说我根据不同服务进行划分,做到了一套封装多次使用
2、参数配置提取
3、解构axios,可以做到到处移植
感谢阅读,喜欢点赞