谈到mock,就不得不讲先后端分离。理想状况下先后端不分离,由全栈的人以product和infrastructure的维度进行开发,效率是最高的。近些年来业务的复杂度愈来愈高,真正的全栈人才极为难招,企业只能退而求其次,对开发进行分工细化,让每一个人作本身最擅长的事,前端负责UI显示和交互,后端负责业务的逻辑、性能等,从而架构上达到更高的效率。同时因为分工的细化,致使先后端的沟通成本增长,代码的控制权一般在后端,一次小的修改可能致使先后端反复沟通,下降开发效率,就产生了先后端分离的方案。先后端分离经过约定好协议,使用约定的协议进行并行开发,将沟通最后阶段放在联调,节省了大量的时间。javascript
分离的表现主要是视图层的控制交给前端,对于一些偏应用类项目,使用ajax请求,先后端各负责本身的部分,直接达到分离状态,而一些展现类系统,受到seo和用户体验的影响,分离只能达到部分分离,如fis方案。不论是哪一种状态的分离,都须要进行协议约定,以达到业务的并行开发。对于前端来讲,开发的效果更多依赖于数据,想要最大程度的减小联调时间,就须要根据协议生成数据,这也就是mock的需求。html
这里借用yapi的流程图(yapi表示mock服务):
前端
首先,先后端进行定制接口,定制完成后各自进行开发。前端的开发者使用mock数据进行开发,开发完成后进行真实环境的联调,找出开发中的问题,再进行测试、上线等流程。java
直接数据写在代码中(或者独立的文件,代码中手动引入),修改代码跳过接口请求,直接使用数据。这种方式的最大问题是耦合性太强,业务代码中混杂了mock数据,每次正式提交都要保证代码数据指向是正确的,不然会产生神奇的结果。同时不是真正发出网络请求,和真实环境有差别。建议仅在没有其余方式的状况下才使用。node
这种方式分为拦截到本地和拦截到其余服务器。相较于硬编码,拦截式下降了mock数据和业务代码的耦合性,只须要引入拦截的代码,将请求转发至本地,至本地文件或其余服务器。这种方案的主要问题是须要针对代码使用的各类库进行定制插件,初期成本高;同时有部分的代码入侵,须要保证入库代码正确。jquery
拦截至数据文件:
最典型的是Mock.js。这种方式实现了自由编写数据,灵活性比较大,并且mock的数据文件能够同步至仓库中,下次开发时。缺点是一样非网络请求,真实性不足。webpack
拦截并改变请求:
这种方式之因此出现是由于服务器的URL和本机的URL规则不一样,须要按照规则进行转换。这种方式与真实状况比较接近,同时产生了跨域,须要服务端提供对应的header。ios
这种方式在公用文件中直接添加接口前缀,依赖于特定的库功能(或者达到相同效果的代码结构)。同以前的拦截并改变请求相似,但更为简单一些,只改前缀就能够了,一样有代码入侵的问题。nginx
这种方式分为两种:使用本地或软件数据和代理转发git
使用本地或软件数据:
最经常使用的如:fiddler, charles, whistle等,能够将请求返回指定内容。主要问题是配置比较繁琐,全部操做都在本机,同步困难。
代理转发:
这种方式和真实环境极为接近,毕竟纯静态的文件,在服务端也是须要进行代理转发的。可以使用的工具就比较多了,使用支持代理转发的开发工具,或者使用上面提到的工具,一样可以将数据转发出去。这种方式最大的优势是:无跨域、能发出真实请求、与业务代码彻底隔离。
对比以上几种方案,最优的选用代理转发方式,其次是代码拦截方式。拦截至数据文件有个优点就是能够将mock数据和仓库同步,但在不一样分支开发时Mock数据可能会冲突。代理转发和拦截至服务器使用最方便,但它须要mockServer。只视开发状况而定。
mock的实现很是多,基本上每套完善的前端开发工具都是自带mock的机制。近几年随着nodejs的流行,前端能够很是方便的实现本身的mockServer,因此想列举出全部的仍是很困难的,这里介绍一些知名字较高的工具。
介绍: 提到mock,就不得不提到swagger (https://swagger.io/)。它是一个极为流行的一个API设计开发工具,覆盖了从设计到文档到测试部署。它是这样介绍的:
Swagger is the world’s 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结构数据,配合相应的工具来实现相似的效果。
介绍:这款在国外用的比较多一些,功能也是比较强大:
Apiary.io平台具备协同设计、即时API模拟、快速生成源码、自动测试和代码调试的开源设计工具,最重要的是能够在线模拟测试,由于该平台具有模拟服务器测试服务,能够把设计好的程序在线测试、验证。
介绍:这是去哪团队作的,使用了nodejs+mongodb方式开发,主要特性:
- 基于 Json5 和 Mockjs 定义接口返回数据的结构和文档,效率提高多倍
- 扁平化权限设计,即保证了大型企业级项目的管理,又保证了易用性
- 相似 postman 的接口调试
- 自动化测试, 支持对 Response 断言
- MockServer 除支持普通的随机 mock 外,还增长了 Mock 指望功能,根据设置的请求过滤规则,返回指望数据
- 支持 postman, har, swagger 数据导入
- 免费开源,内网部署,信息不再怕泄露了
有了各类极为方便使用的mockServer,想要接入就很简单了。mockServer的通常使用规则:
拦截式针对的是使用一些封装过的ajax库,好比jquery、axios,或者使用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标签便可(部分拦截可能须要引入多个标签)。
这种状况适合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。
代理转发实现的前提是你使用的开发工具支持转发,若是不支持,就须要使用Fiddler、charles等工具进行规则重写。下面举一些例子:
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熟悉以前的业务界面,或者查看一些表现特殊的界面,最大程度减小对后端的依赖。
上面介绍的几款mockServer有几种都是使用nodejs开发的。和其余语言开发的mock服务相比,json格式成为书写的主要格式,虽然用起来容易,但书写上并不方便(json5格式在某种程度上加强了书写体验,但相比yaml等格式仍是有所不足)。同时业务状况不一样,针对性的选择不一样的平台,推荐使用rap2和yapi,前者界面更为简洁,操做方便,后者功能更为强大。若是有特殊的须要,能够本身写一个,顺便练练手。
【你是如何构建 Web 前端 Mock Server 的? - 莫池宇的回答 - 知乎
https://www.zhihu.com/question/35436669/answer/235608128】