前语:
咱们知道软件通常是在灵敏、竞赛剧烈的环境中开发的,现在许多时分咱们许多开发都是前后端分离的,在前后端完成后就要马上进行联调测试上线等,那么这个时分一款好的mock东西就尤其重要了。
现有计划
1.直接在项目中界说数据
这种就很常见了,在接口完成之后,咱们再将数据进行删去重接口中获取数据,这样在联调的时分工作压力都比较大,而且出错率高。
2.经过脚手架的装备文件进行mock
现在许多的公司脚手架其实都有供给mock的文件夹,在里面增加需求mock的接口,匹配到规矩的恳求就能够进行模仿,这种在联调的时分只需求将mock的数据注释即可,可是在开发的时分很不便利,经过打包东西的装备,大部分是静态加载的,不能支撑HMR,每次修正都需求重新发动项目,如果项目庞大的话发动一次就能够摸鱼好久。
3.经过抓包东西进行模仿
经过一些流行的抓包东西fiddler进行模仿,对应书写相应的mock规矩,这样就能够完成mock,联调的时分也很简略,封闭抓包东西就行了,和项目脱离不存在啥HMR,和代码0耦合能够说是很棒的办法了,就是有必定的上手本钱。
4.基于server worker进行mock
利用标准化的 Service Worker API,该 API 旨在阻拦网络等级的恳求,从而使模仿彻底无缝。这不只保证了运用和不运用模仿时应用程序的行为相同,而且不需求为了模仿而对应用程序代码进行任何更改。观察 DevTools 的“网络”中的恳求,能够说是现已忘了这是模仿了。这种能够说是很帅的操作了,对应模仿的数据还能够在开发者东西中进行检查。可是也是有缺点的就是必须要项目中开放一个public文件存放service worker文件,由于创立worker和sw文件需求在同一个源下,这儿不进行展开,有爱好能够学习下service worker的相关内容。这儿贴一个现已成熟的计划:msw。
5.浏览器插件mock
经过浏览器插件进行mock,这种mock办法在我看来比前面的几种都是要好的,主要长处有以下几点:。。。。。。。
哈哈哈是下面这儿:
- 关于项目代码是0入侵的,这个只有上面的抓包东西能够做到。
- 简略易于操作,咱们只需求在插件中输入对应 URL匹配规矩即可进行阻拦,还有个更棒的功用就是其供给的阻拦恳求回来功用,要知道咱们许多时分是对原有接口的小修小改,那么咱们能够直接把阻拦拿到该恳求的呼应内容进行更改能够说是相当便利了。
- 便于团队协作。咱们的mock数据要支撑导入导出功用,便于团队中协作。这一点他的作用就没有前面在项目中依赖那么好,咱们只能导出对应的JSON文件进行分享,而前面的咱们能够直接在版本操控器中一起流通。
官网对插件的运用也是介绍的很明白,感爱好的自己学习运用:tweak,可是它的有些功用是收费的,不保证今后根底功用也收费,而且在阻拦恳求的时分有些卡顿。
正文开端
讲了这么多种计划你不会认为我要进行总结了吧?咱们前面说了许多种计划,其中我觉得最好的就是最终一种,可是它没有开放的源码,且收费(这很难受),作为一个切图仔,我觉得这样的功用完成起来应该也是不难的,所以动手完成了一个简易版的mock插件,由于日常中咱们最经常运用的基本都是XHR,所以我连fetch的都没做哈哈,后续有时间再加了,最主要就是完成两个功用:1.获取原有恳求的呼应体能够进行更改;2.能够操控恳求的呼应内容;咱们先看下作用:
能够看到一开端的时分咱们的恳求回来的是一个html这其实是脚手架对资源恳求找不到的默认恳求,咱们经过点亮绿色图标阻拦到了刚才的两个恳求内容,由于不是可解析的JSON数据,所以填写上默认值,否则就是原有内容(注意我这儿的修正JSON比5的好用,他的不会错误提示哈哈)。然后咱们敞开mock按钮再次恳求的时分咱们的数据就变成咱们的mock数据了,是不是很帅。
简略的讲下完成思路
首要关于恳求的呼应浏览器插件是不允许咱们进行获取的(虽然其有供给恳求完成的事情监听,可是你拿不到对应的呼应内容,这样就不能做呼应内容的回显了)。这儿我本来还想经过service worker来获取呼应内容以及改动呼应内容,咱们知道这关于service worker是十分简略的,咱们只需求监听fetch事情,可是我试了许多办法都被其同源策略约束了,要是有大佬知道怎样操作,评论区求教下。最终是经过注入js脚本,修正XHR目标完成的,咱们只需求修正XHR目标的办法,在恳求成功的时分获取对应的呼应内容,发回咱们的浏览器popup中,咱们就能做到回显呼应内容,再在修正对应的需求mock的恳求呼应内容就能完成咱们的mock操作,讲的很抽象,咱们直接看代码:
1.获取呼应内容:
(function (xhr) {
var XHR = XMLHttpRequest.prototype;
var open = XHR.open;
var send = XHR.send;
XHR.open = function (method, url) {
this._method = method;
this._url = url;
return open.apply(this, arguments);
};
const filterUrl = ['xxx.com'];//这儿我是把一些必定不要阻拦的恳求给过滤掉,原因是在实在项目中太多无关的恳求了,比方啥埋点上报啥的一大堆
XHR.send = function (postData) {
this.addEventListener('loadend', function (e) {
const data = e?.target?.response;
if(!filterUrl.some(item=>this._url.includes(item)))
{
window.postMessage({label: this._url, value: data}, '*'); // 将呼应发送到 content script
}
});
return send.apply(this, arguments);
};
})(XMLHttpRequest);
咱们只要在恳求loadend的时分把对应的呼应内容进行回传即可。
2.mock数据
(function startMockOnreadystatechange() {
const originOpen = XMLHttpRequest.prototype.open;
const setWriteKeys = ['status', 'statusText', 'response', 'responseText', 'readyState','onload'];
XMLHttpRequest.prototype.open = function (_, url) {
const localDataStr = localStorage.getItem('cai_mock_data');
const localData = JSON.parse(localDataStr);
originOpen.apply(this, arguments);
const find = localData?.find(item => url.includes(item.url));
if (find&&find.startMock) {
// 把这堆特点改为可写
setWriteKeys.forEach(key => {
const props = Object.getOwnPropertyDescriptor(this, key);
Object.defineProperty(this, key, {
...props,
writable: true,
readable: true,
});
});
setTimeout(() => {
// 手动改动呼应状况和值
this.status = 200;
this.readyState = 4; // 原生xhr中该值改动,会触发onreadystatechange办法
this.statusText = 'OK';
this.response = find.json;
this.responseText = find.json;
// 手动触发会onreadystatechange办法
this.dispatchEvent(new Event('readystatechange'));
});
}
};
})(XMLHttpRequest);