1. 有什么好处
本地接口模拟最大的好处就是能够使前后端项目解耦,前端更专注于开发,减少线上调试,以此提升开发效率。
2. 有哪些途径
本地接口模拟一般分为工具层面和代码层面。
3. 工具层面
就工具层面而言,一般是由项目的构建工具提供的功能。比如,当我们用 webpack-dev-server、webpack-dev-middleware + browser-sync 等工具时,就可以向工具里添加本地接口模拟功能。
注:这里不讲解工具如
webpack-dev-server
、webpack-dev-middleware
+browser-sync
等的用法,如有需要,可以自己去了解一下
下面以 webpack-dev-server
为例进行讲解,其他工具类似。
3.1 静态文件
最简单的,我们可以用静态 json
文件做本地接口模拟功能。
1 | |-- / # 项目根目录 |
然后用 webpack-dev-server
以项目根目录为基地址来开启本地开发调试,在页面中就可以这样访问:
1 | fetch('/mock/1.json'); // 访问 1.json |
这种方式可以访问项目中所有的文件,不光是 json
文件,其他的如 html
、js
、css
之类的文本文件、如图片之类的二进制文件也可以访问。另外,只要文件有更新,刷新浏览器页面就可以重新获取新的文件,没有缓存。
因为本地接口模拟功能主要是针对的返回值为 json
格式的异步请求,所以这种方式主要用 json
文件。
这种方式是最简单、快捷、使用难度最低的方式。
3.2 动态注册接口
使用静态文件做本地接口模拟功能主要存在以下的一些问题:
- 静态文件只能以
get
方法访问 - 输入数据是静态的,不能做运算、循环、判断等,也不能根据请求参数做出不同的响应
- 本地接口名与服务器上的接口名不一样,这就比较麻烦了,每次上线到服务器的时候都得改接口名
所以,多数情况下,都会采用动态注册接口的方式做本地接口模拟功能。
这种方式是用 js
文件编写一系列的 路由 => 响应
映射,然后动态的把定义好的接口注册到工具实例中。
目录结构:
1 | |-- / # 项目根目录 |
示例 mock
文件的写法(可以自定规范,下面只是演示):
1 | # mock/user.js |
注:
- 上面的写法只是示例,可以自定规范、书写格式等
- 可以用 mockjs 库来帮助生成假数据
webpack-dev-server
的相关配置:
1 | # webpack.config.js |
然后用 webpack-dev-server
开启本地开发调试,在页面中就可以这样访问:
1 | fetch('/user/profile'); // 访问 /user/profile |
一般来说,我们还会用上 chokidar 来监听 mock
目录下的文件变动,来更新路由及其响应,以此能够做到每次访问到的都是最新的资源(因为 node
针对某个模块只会加载一次)。
1 | const chokidar = require('chokidar'); |
这种方式比较复杂,尤其是对项目搭建者要求比较高,需要对相关工具有深入的了解,好在社区已经有封装好的工具:roadhog。
但这种方式对使用者是很棒的,因为能够完全模拟服务器接口,包括接口名、HTTP 方法、参数、返回值等,所以同样的代码既可以在本地运行,也可以在服务器上运行。
所以,这也是比较推荐的方式。
注:上面的代码只是演示构建过程,并不保证可以运行
3.3 使用代理
这种方式是把本地模拟文件写在另一个单独项目里,然后使用使用代理的方式,访问模拟接口。
mock
项目(以 koa 为例):
1 | const Koa = require('koa'); |
app
应用项目:
webpack-dev-server
的相关配置:
1 | # webpack.config.js |
然后用 webpack-dev-server
开启本地开发调试,在页面中就可以这样访问:
1 | fetch('/api/user/profile'); // 访问 mock 项目的 /api/user/profile |
一般来说,我们还会用上 nodemon 来监听 mock
项目中的文件变动,自动重启 mock
应用程序,以此能够做到每次访问到的都是最新的资源(因为 node
针对某个模块只会加载一次)。
1 | nodemon app.js |
这种方式可以统一管理多个项目的数据模拟文件,多个项目可以共享一些模拟数据。
3.4 线上接口模拟
有些时候,当我们在产品环境的时候(在线上)也可能想用模拟数据(比如 APP、微信小程序、用于演示的 web 应用等),或者需要一个线上的地方来统一管理模拟数据时,就需要线上接口模拟了。
线上接口模拟拥有完备的 UI 操作界面,可以添加多个用户、多个团队、多个仓库,可以生成为每一个请求参数添加类型限定、描述,为响应数据字段添加描述等。
因为是在线上的模拟数据,所以在任何地方都可用,不管是本地开发,还是线上调试、演示,都是可用的。
比较有名的线上接口模拟工具有:
- easy-mock:线上演示地址 https://easy-mock.com/
- RAP / rap2-delos + rap2-dolores:阿里出品,线上演示地址 http://rap2.taobao.org/
3.4.1 easy-mock
环境需求:Node.js (>= v8.9) & MongoDB (>= v3.4) & Redis(>= v4.0)
安装步骤请参考官方的文档 easy-mock#quick-start
easy-mock
主要提供了以下的一些功能:
- 支持接口代理
- 支持快捷键操作
- 支持协同编辑
- 支持团队项目
- 支持 RESTful
- 支持 Swagger | OpenAPI Specification (1.2 & 2.0 & 3.0)
- 基于 Swagger 快速创建项目
- 支持显示接口入参与返回值
- 支持显示实体类
- 支持灵活性与扩展性更高的响应式数据开发
- 支持自定义响应配置(例:status/headers/cookies)
- 支持 Mock.js 语法
- 支持 restc 方式的接口预览
3.4.2 RAP / rap2-delos + rap2-dolores
环境需求:Node.js (>= v8.9) & MySQL (>= v5.7) & Redis(>= v4.0)
RAP 目前有两个版本,第一个版本的 RAP 已经被官方废弃了,建议用第二个版本。
RAP2 分成了两个包:
- rap2-delos:后端数据 API 服务器
- rap2-dolores:前端静态资源
RAP2 的安装步骤要麻烦一些,rap2-delos
可以参考官方文档 rap2-delos#部署、非官方 rap2-delos 部署文档,rap2-dolores
可以参考官方文档 rap2-dolores#deployment-部署。
RAP2 提供了与 easy-mock
类似的功能,但比 easy-mock
要更强大一些,当然也要复杂一些,比如:
- 对请求参数支持更完备,比如
headers
、query params
、body params
- 对响应数据支持更完备,比如可以为每个字段添加描述、限定类型等
3.4.3 两者之间比较
RAP2 比 easy-mock
要更强大一些,但也要复杂一些,所以追求功能完备的可以用 RAP2,追求简单快捷的可以用 easy-mock
。
4. 代码层面
从上面可以看出,除了第二种方式 动态注册接口
之外,其他的方式都不能做到完全模拟服务器环境,至少服务器接口地址与本地模拟地址不一样,这就有一个问题:每次上线前都得改成服务器地址。
另外,前端与后端对接的过程中也总是难免会遇到一些问题:
- 前端传的参数与后端所需的参数难以保持一致:比如分页,前端定的
page
、从 1 开始,后端定的pageNum
、从 0 开始 - 前端需要的数据与后端返回的数据相差很大,需要对返回的数据做处理
- 后端可能更改字段名或者数据类型,导致前端要查找、并更新相应的代码
一种好的、解决这些问题的方式是对应用进行分层、把异步请求进行隔离封装。
我一般会用 see-fetch、see-ajax 对异步请求进行隔离封装。
注:see-fetch 是对 window.fetch
的封装,see-ajax 是对 XMLHttpRequest
对象的封装。
4.1 以 see-fetch 为例进行说明:
可以在代码中设置多个内部环境,然后针对不同的外部环境设置不同的内部环境(如:本地环境、线上环境等),这样就可以做到不改代码,只改一个环境值。
如果搭配 define-plugin,连环境值都不需要改,直接由 define-plugin
在运行的过程中指定。
1 | import seeFetch from 'see-fetch'; |
配置一个异步请求:
1 | seeFetch.config(name, { // 定义一个名为 name 的异步请求(下面的配置可以是多环境,每个环境可以设置不同的值) |
发起访问:
1 | seeFetch(name, params).then(result => { |
从上面可以看出:一个请求的不确定性都被封装到了配置中,不管是接口地址更新、前端请求参数与后端不一致、后端响应数据与前端所需的差异很大等,都可以在配置中进行操作,而丝毫不需要改其他地方的代码。
这样,如果后端接口有什么改动的,只需要找到配置文件进行更新,而不用在项目中找哪里使用了这个接口。
如此,既能很好的使用本地数据模拟,也可以从容应对后端接口的改动,便能事半功倍。