谈到 mock, 就不得不讲前后端分离理想情况下前后端不分离, 由全栈的人以product 和 infrastructure 的维度进行开发, 效率是最高的近些年来业务的复杂度越来越高, 真正的全栈人才极为难招,企业只能退而求其次, 对开发进行分工细化, 让每个人做自己最擅长的事, 前端负责 UI 显示和交互, 后端负责业务的逻辑性能等, 从而架构上达到更高的效率同时由于分工的细化, 导致前后端的沟通成本增加, 代码的控制权通常在后端, 一次小的修改可能导致前后端反复沟通, 降低开发效率, 就产生了前后端分离的方案前后端分离通过约定好协议, 使用约定的协议进行并行开发, 将沟通最后阶段放在联调, 节省了大量的时间
分离的表现主要是视图层的控制交给前端, 对于一些偏应用类项目, 使用 ajax 请求, 前后端各负责自己的部分, 直接达到分离状态, 而一些展示类系统, 受到 seo 和用户体验的影响, 分离只能达到部分分离, 如 fis 方案不管是哪种状态的分离, 都需要进行协议约定, 以达到业务的并行开发对于前端来说, 开发的效果更多依赖于数据, 想要最大程度的减少联调时间, 就需要根据协议生成数据, 这也就是 mock 的需求
使用 mock开发流程
这里借用 yapi 的流程图(yapi 表示 mock 服务):
首先, 前后端进行定制接口, 定制完成后各自进行开发前端的开发者使用 mock 数据进行开发, 开发完成后进行真实环境的联调, 找出开发中的问题, 再进行测试上线等流程
常用的mock 方式
1. 代码层硬编码
直接数据写在代码中(或者独立的文件, 代码中手动引入), 修改代码跳过接口请求, 直接使用数据这种方式的最大问题是耦合性太强, 业务代码中混杂了 mock 数据, 每次正式提交都要保证代码数据指向是正确的,否则会产生神奇的结果同时不是真正发出网络请求, 和真实环境有差异建议仅在没有其他方式的情况下才使用
2. 代码中针对使用的ajax 库拦截
这种方式分为拦截到本地和拦截到其他服务器相较于硬编码, 拦截式降低了 mock 数据和业务代码的耦合性, 只需要引入拦截的代码, 将请求转发至本地, 至本地文件或其他服务器这种方案的主要问题是需要针对代码使用的各种库进行定制插件, 初期成本高; 同时有部分的代码入侵, 需要保证入库代码正确
拦截至数据文件:
最典型的是 Mock.js 这种方式实现了自由编写数据, 灵活性比较大, 而且 mock 的数据文件可以同步至仓库中, 下次开发时缺点是同样非网络请求, 真实性不足
拦截并改变请求:
这种方式之所以出现是因为服务器的 URL 和本机的 URL 规则不同, 需要按照规则进行转换这种方式与真实情况比较接近, 同时产生了跨域, 需要服务端提供对应的 header
3. 为所有接口统一添加前缀
这种方式在公用文件中直接添加接口前缀, 依赖于特定的库功能 (或者达到相同效果的代码结构) 同之前的拦截并改变请求类似, 但更为简单一些, 只改前缀就可以了, 同样有代码入侵的问题
4. 使用其他工具
这种方式分为两种: 使用本地或软件数据和代理转发
使用本地或软件数据:
最常用的如: fiddler, charles, whistle 等, 可以将请求返回指定内容主要问题是配置比较繁琐, 所有操作都在本机, 同步困难
代理转发:
这种方式和真实环境极为接近, 毕竟纯静态的文件, 在服务端也是需要进行代理转发的可使用的工具就比较多了, 使用支持代理转发的开发工具, 或者使用上面提到的工具, 同样能够将数据转发出去这种方式最大的优点是: 无跨域能发出真实请求与业务代码完全隔离
方案对比
对比以上几种方案, 最优的选用代理转发方式, 其次是代码拦截方式拦截至数据文件有个优势就是可以将 mock 数据和仓库同步,但在不同分支开发时 Mock 数据可能会冲突代理转发和拦截至服务器使用最方便, 但它需要 mockServer 只视开发情况而定
一些 mock 用工具
mock 的实现非常多, 基本上每套完善的前端开发工具都是自带 mock 的机制近几年随着nodejs 的流行, 前端可以非常方便的实现自己的 mockServer, 所以想列举出所有的还是很困难的, 这里介绍一些知名字较高的工具
1. swagger
地址:[https://swagger.io/]
介绍: 提到 mock, 就不得不提到 swagger (https://swagger.io/)它是一个极为流行的一个 API 设计开发工具, 覆盖了从设计到文档到测试部署它是这样介绍的:
Swagger is the worlds largest framework of API developer tools for the OpenAPI Specification(OAS), enabling development across the entire API lifecycle, from design and documentation, to test and deployment.
在设计 RESTFUL 类型的 API极为有用, 它没有专门提供 mock 服务,但可以提供 mock 服务的 server 模板代码, 可根据模板自行搭建 mock-server 此外, 还提供相关的 API 的 JSON 结构数据, 配合相应的工具来实现类似的效果
2. Mock.js
地址: https://github.com/nuysoft/Mock/tree/refactoring
介绍:THX 团队出品, 本地文件编写 mock 数据规则, 适用于代码库拦截,之前较为流行的一个方案, 很多工具都集成了 Mockjs 语法, 目前仓库已经不再更新
3. rap2
地址: https://github.com/thx/rap2-delos
介绍: 同 THX 团队出品, 是 rap0.x 的升级版本, 使用了 nodejs 和关系数据库开发, 兼容 mock.js 语法界面比较简洁, 交互友好, 支持界面式编辑 API 但 URL 设计与原URL 不同, 需要使用代码库拦截方式
4. apiary
地址: https://app.apiary.io/
介绍: 这款在国外用的比较多一些, 功能也是比较强大:
Apiary.io 平台具有协同设计即时 API 模拟快速生成源码自动测试和代码调试的开源设计工具, 最重要的是可以在线模拟测试, 因为该平台具备模拟服务器测试服务, 可以把设计好的程序在线测试验证
5. easy-mock
地址: https://easy-mock.com/
介绍: 搜车出品, rest api 模拟, 基于 mockjs 语法, 能够从 swagger 生成简单数据
6. yapi
地址: http://yapi.qunar.com/getfamiliar.html
介绍: 这是去哪团队做的, 使用了 nodejs+mongodb 方式开发, 主要特性:
基于 Json5 和 Mockjs 定义接口返回数据的结构和文档, 效率提升多倍
扁平化权限设计, 即保证了大型企业级项目的管理, 又保证了易用性
类似 postman 的接口调试
自动化测试, 支持对 Response 断言
MockServer 除支持普通的随机 mock 外, 还增加了 Mock 期望功能, 根据设置的请求过滤规则, 返回期望数据
支持 postman, har, swagger 数据导入
免费开源, 内网部署, 信息再也不怕泄露了
rap2 和 yapi 的一些对比
接入 mockServer
有了各种极为方便使用的 mockServer, 想要接入就很简单了 mockServer 的一般使用规则:
URL 相同, 直接代理转发即可
URL 后半部分相同, 直接加上 URL 前缀即可
URL 规则不同, 或需要身份认证, 需要拦截转发
拦截式
拦截式针对的是使用一些封装过的 ajax 库, 比如 jqueryaxios, 或者使用 fetch 库实现的方式各有不同如果使用的是支持拦截器模式(如 axios), 拦截代码就比较简单了, 直接在拦截器中改变 URL 指向即可, 指向 mockServer 或 mockjs 文件见以下代码(以下代码是摘自 rap 或 rap2 等其他库)
- function wrapAxios(axios) {
- var url = ''
- var oldRequest = {}
- var routePassed = false
- axios.interceptors.request.use(function (config) {
- url = config.url
- config.url = "http://" + ROOT + '/mockjsdata/' + projectId + url;
- oldRequest = Object.assign({}, config)
- return config;
- }, function (error) {
- return Promise.reject(error);
- });
- axios.interceptors.response.use(function (res) {
- return res;
- }, function (error) {
- return Promise.reject(error);
- });
- }
对于一些不支持拦截器的, 或者原生的方法 fetch, 通过覆盖的方式实现(https://github.com/wenlonghuo/rap2-delos/blob/master/public/libs/fetch.rap.js):
- ;(function (RAP, fetch) {
- if (!fetch) {
- console.warn('当前环境不支持 fetch')
- return
- }
- if (!RAP) {
- console.warn('请先引入 RAP 插件')
- return
- }
- let next = fetch
- let find = (settings) => {
- for (let repositoryId in RAP.interfaces) {
- for (let itf of RAP.interfaces[repositoryId]) {
- if (itf.method.toUpperCase() === settings.method.toUpperCase() && itf.url === settings.url) {
- return Object.assign({}, itf, { repositoryId })
- }
- }
- }
- }
- window.fetch = function (url, settings) {
- // ajax(settings)
- if (typeof url === 'object') {
- settings = Object.assign({ method: 'GET' }, url)
- } else {
- // ajax(url) ajax(url, settings)
- settings = Object.assign({ method: 'GET' }, settings, { url })
- }
- var match = find(settings)
- if (!match) return next.call(window, url, settings)
- let redirect = `${RAP.protocol}://${RAP.host}/app/mock/${match.repositoryId}/${match.method}/${match.url}`
- settings.credentials = 'include'
- settings.method = 'GET'
- settings.dataType = 'jsonp'
- console.log(`Fetch ${match.method} ${match.url} => ${redirect}`)
- return next.call(window, redirect, settings)
- }
- })(window.RAP, window.fetch)
使用这些插件的方法很简单, 直接在 html 最后添加指向的 script 标签即可(部分拦截可能需要引入多个标签)
修改全局 URL 式
这种情况适合 mockServer 请求中需要添加 baseURL 的类型对于支持 baseURL 类型的库, 设置 baseURL 即可如 baseURL 为:
http://yapi.demo.qunar.com/mock/1304
我们业务代码中请求的 api 为:
/weather/api
那么我们实际请求的地址是:
http://yapi.demo.qunar.com/mock/1304/weather/api
所以我们应该这么设置(以 axios 为例):
- export default axios = new Axios({
- baseURL: process.env.NODE_ENV === 'development' ? 'http://yapi.demo.qunar.com/mock/1304' :
- })
如果是不区分环境的情况下, 需要在提交前将 baseURL 设置为空, 以免影响仓库代码
对于不支持 baseURL 的库, 建议封装方法, 单独保存 baseURL
代理转发式
代理转发实现的前提是你使用的开发工具支持转发, 如果不支持, 就需要使用 Fiddlercharles 等工具进行规则重写下面举一些例子:
webpack-dev-server 中:
- proxy: {
- "/api": "http://localhost:3000"
- }
- proxy: {
- "/api": {
- target: "http://localhost:3000",
- changeOrigin: true
- }
- }
注: changeOrigin 是 http-proxy 设置选项, 表示在请求头中将 host 转换为目标服务器的地址或 IP, 解决服务器出现请求地址找不到的问题
nginx(应该没人用吧):
- location /api {
- proxy_set_header X-Forwarded-Proto https;
- proxy_set_header Host $host;
- proxy_set_header X-Real-Ip $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Host $server_name;
- proxy_pass http://localhost:11011;
- proxy_redirect off;
- }
fiddler 中在右侧的 tab 页中选择 autoResponder 标签页编辑 rule 分别输入
- REGEX:^https://server\.example\.com/(.*)
- http://www.target.com:3838/$1
mock 的一些问题
mock 不能替代联调尽管 mock 数据再真实, 也无法实现和后端接口一样的逻辑, 部分逻辑检查或业务的问题只能联调才能发现
mock 不能替代测试 mock 本身是为了加快开发速度,那些对于代码质量要求比较高的项目, mock 服务只能提供一些 case
总结
使用 mock 前提是前后端有一个明确的接口协议, 利用合适的工具才能提高开发效率强大的 mock 服务可以使你对开发的代码更为自信, 即使没有后端, 新手就可以通过 mock 熟悉之前的业务界面, 或者查看一些表现特殊的界面, 最大程度减少对后端的依赖
上面介绍的几款 mockServer 有几种都是使用 nodejs 开发的和其他语言开发的 mock 服务相比, json 格式成为书写的主要格式, 虽然用起来容易, 但书写上并不方便 (json5 格式在某种程度上增强了书写体验, 但相比 yaml 等格式还是有所不足) 同时业务情况不同, 针对性的选择不同的平台, 推荐使用 rap2 和 yapi, 前者界面更为简洁,操作方便, 后者功能更为强大如果有特殊的需要, 可以自己写一个, 顺便练练手
搭建一个属于自己的 server
参考
你是如何构建 Web 前端 Mock Server 的? - 莫池宇的回答 - 知乎
https://www.zhihu.com/question/35436669/answer/235608128
来源: https://www.cnblogs.com/dreamless/p/8487322.html