前端项目中如何优雅地封装接口请求?一篇讲清 JS 请求管理思路

张开发
2026/4/16 2:22:21 15 分钟阅读

分享文章

前端项目中如何优雅地封装接口请求?一篇讲清 JS 请求管理思路
在前端开发中接口请求几乎贯穿了所有业务页面。列表查询、详情回显、表单提交、删除操作本质上都离不开请求后端接口。很多项目在初期为了赶进度往往会把请求直接写在页面里。页面一多问题就慢慢暴露出来了请求逻辑重复、接口地址分散、异常处理混乱、loading状态难维护最后整个页面会变得越来越难改。这篇文章只聊一件事前端项目中如何更规范地处理接口请求。一、为什么不建议在页面里直接写请求很多人一开始会这样写axios.post(/xxx/list,params).then(res{this.tableDatares.data})这种写法短期看没问题但一旦项目变大很容易出现以下问题接口地址分散在各个页面中不方便统一维护页面里既有业务逻辑又有请求细节可读性差相同接口调用方式重复书写复用性差后续如果要统一加 token、错误提示、请求拦截改动范围会很大页面代码越来越臃肿不利于排查问题所以更推荐的方式是把接口请求统一封装再由页面按需调用。二、接口请求为什么要单独封装在实际项目中比较常见的做法是把接口统一放到api目录下按模块拆分文件。页面只负责调用接口方法不直接关心底层请求实现。例如我们可以这样封装一个接口方法importrequestfrom/utils/requestexportfunctiongetListApi(params,data){returnrequest({url:/module/list,method:post,params,data})}这种方式的优势非常明显请求地址集中管理方便维护页面中调用语义更清晰相同接口可以多处复用方便统一处理请求头、鉴权、拦截器页面代码更专注于业务逻辑本身简单来说接口封装的核心价值就是解耦。页面负责“用”接口文件负责“管”。三、一个项目里的接口请求通常分为哪几层如果想让请求逻辑更清晰通常可以分为三层1. 请求工具层这一层一般是对axios的再次封装主要负责基础地址配置超时时间配置请求头统一处理token 注入请求拦截和响应拦截通用错误提示例如importaxiosfromaxiosconstserviceaxios.create({baseURL:/api,timeout:10000})exportdefaultservice这一层通常不会写具体业务只负责“底层能力”。2. 接口模块层这一层是把每个业务模块的接口单独封装成方法。importrequestfrom/utils/requestexportfunctiongetListApi(params,data){returnrequest({url:/module/list,method:post,params,data})}exportfunctiondeleteApi(id){returnrequest({url:/module/delete?id${id},method:get})}这一层的作用是把具体业务接口抽象成可调用的方法。3. 页面调用层这一层就是我们日常写页面逻辑的地方。页面只关心什么时候发请求请求成功后如何赋值请求失败后如何提示是否展示loading例如getList(){this.loadingtruereturngetListApi(this.page,this.formData).then((res){if(res.code200){this.tableDatares.rows}else{this.$message.error(res.msg)}}).finally((){this.loadingfalse})}这种写法结构很清晰职责也很明确。四、为什么loading最好放在finally中处理很多人在写接口请求时习惯在then里关闭loadinggetList(){this.loadingtruegetListApi().then(res{this.loadingfalsethis.tableDatares.rows})}这并不是完全错误但它有明显风险。因为只有在请求成功进入then时这段代码才会执行。如果出现下面这些情况网络异常接口超时服务端报错请求被拦截器拦截业务处理过程中抛出异常那么this.loading false就可能执行不到页面会一直处于加载状态。因此更稳妥的写法是把关闭loading放进finallygetList(){this.loadingtruereturngetListApi().then((res){if(res.code200){this.tableDatares.rows}}).finally((){this.loadingfalse})}为什么推荐这样写因为finally的作用就是无论请求成功还是失败只要这次 Promise 结束了都会执行这里的代码。这就非常适合放一些“收尾动作”比如关闭loading关闭弹层加载态清理临时状态还原按钮禁用状态所以页面中凡是涉及异步请求的状态收尾优先考虑finally会更稳。五、一个更推荐的接口请求思路在实际开发中我更推荐采用这样的思路1. 所有请求都走统一请求工具这样便于统一处理tokenbaseURL超时通用错误拦截器逻辑2. 所有业务接口都单独封装方法不要把接口地址散落在页面里。页面应该调用方法而不是直接拼请求配置。3. 页面只负责业务数据处理页面中最重要的是“业务表达”而不是请求细节。4. 所有异步状态收尾统一放到finally尤其是loading按钮禁用状态上传遮罩层弹框中的处理中状态这一步非常关键能明显减少异步状态异常。六、总结前端接口请求看起来只是“调一下接口”但真正决定代码质量的是请求背后的组织方式。一个更规范的接口请求结构通常具备这些特点请求工具统一封装业务接口按模块统一管理页面调用逻辑清晰简单loading状态有统一收尾页面不直接堆砌请求细节如果只是小 demo怎么写都能跑但如果是实际业务项目接口请求这部分越早规范后续维护成本就越低。前端开发写到最后拼的往往不是“能不能实现”而是“能不能持续维护”。而接口请求的封装方式恰恰就是最能拉开代码质量差距的地方之一。

更多文章