Skip to content

Commit

Permalink
feat: fakeServer 基础功能完成
Browse files Browse the repository at this point in the history
  • Loading branch information
KonghaYao committed Jul 28, 2021
1 parent ed05894 commit 3875af7
Show file tree
Hide file tree
Showing 9 changed files with 2,353 additions and 127 deletions.
9 changes: 7 additions & 2 deletions FakeServer/ajax/DEMO.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { mockFetch } from './fetch/fetch';

mockFetch({
request() {},
response() {},
// request 阶段进行的拦截验证,并向 FakeServer 进行请求
async proxy(url, options) {
const localCallback = await fakeServer.getServerResult(url, options);
if (localCallback) {
return localCallback;
}
},
silent: false,
});
32 changes: 18 additions & 14 deletions FakeServer/ajax/XMLHttpRequest/defineGetterAndSetter.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@
export function defineGetAndSet(XHR) {
// 将这些 键值对 映射到 $data 属性对象的对应值上去
const array = ['readyState', 'status', 'response', 'responseText', 'statusText'];
Object.defineProperties(
XHR,
array.reduce((col, cur) => {
col[cur] = {
get() {
return this.$data[cur];
},
set(state) {
this.$data[cur] = state;
},
};
return col;
}, {}),
);
const auto = array.reduce((col, cur) => {
col[cur] = {
get() {
return this.$data[cur];
},
set(state) {
this.$data[cur] = state;
},
};
return col;
}, {});
Object.defineProperties(XHR, Object.assign(auto));
XHR.getResponseHeader = function (name) {
return this._responseHeaders[name];
};
XHR.getAllResponseHeaders = function () {
return this._responseHeaders;
};
}
60 changes: 26 additions & 34 deletions FakeServer/ajax/XMLHttpRequest/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,48 @@
import { pick } from 'lodash-es';
import { defineGetAndSet } from './defineGetterAndSetter.js';
import HTTP_STATUS_CODES from './constant.js';
let XMLHttpRequest;
let XHR;
const config = {
request: null,
response: null,
silent: false,
};

function makeResponse() {}

// ! 虽然 XMLHttpRequest 不能够修改,但是可以通过设置 getter 和 setter 将属性映射到 $属性上,这样的话,原生 XHR 会将数据写入和读取的位置更改为新的对象属性上,这样就可以被我们修改了。

class MockXMLHttpRequest extends XMLHttpRequest {
class MockXMLHttpRequest extends window.XMLHttpRequest {
constructor(...args) {
super(...args);
}
_responseHeaders = {};
$mock = true; // 标识是否打开拦截
open(method, url, _, username, password) {
// 不进行同步操作
XMLHttpRequest.prototype.open.call(this, method, url, true, username, password);
XHR.prototype.open.call(this, method, url, true, username, password);
this.$data.url = url;
this.$data.method = method.toLowerCase();
}
send(body) {
if (this.$mock) {
const options = pick(this.$data, ['headers']);
const result = config.request(this.$data.url, options);
if (result) {
const options = pick(this.$data, ['headers', 'method']);
// ! 这里的 proxy 中的参数固定为 fetch 中的标准。
const result = config.proxy(this.$data.url, options);

if (result.body) {
defineGetAndSet(this);
this.dispatchEvent(new Event('loadstart'));
setTimeout(this.$done.bind(this), this.timeout || 100);
setTimeout(() => this.$done.bind(this)(result), this.timeout || 100);
return null;
}
// 这里穿透下去
}
XMLHttpRequest.prototype.send.call(this, body);
XHR.prototype.send.call(this, body);
}
setRequestHeader(key, value) {
this.$data.headers[key] = value;
return XMLHttpRequest.prototype.setRequestHeader.call(this, key, value);
}
get $mock() {
return this.$mock;
}
set $mock(value) {
if (typeof value === 'boolean') {
this.$mock = value;
return true;
}
return false;
return XHR.prototype.setRequestHeader.call(this, key, value);
}

$data = {
// 原生属性的 getter 和 setter
readyState: 0,
Expand All @@ -65,34 +57,34 @@ class MockXMLHttpRequest extends XMLHttpRequest {
method: 'get',
};

$done() {
$done({ body, headers, status }) {
// 伪造 XHR 返回事件
this.readyState = this.HEADERS_RECEIVED;
this.dispatchEvent(new Event('readystatechange'));
this.readyState = this.LOADING;
this.dispatchEvent(new Event('readystatechange'));

this.status = 200;
this.statusText = HTTP_STATUS_CODES[200];
// ! 传入创建函数,给与使用者开放权限
const response = config.response(makeResponse);
this.response = response;
this._responseHeaders = headers;
this.status = status;
this.statusText = HTTP_STATUS_CODES[status];
this.response = body;
this.responseText = typeof this.response === 'string' ? this.response : JSON.stringify(this.response);
this.readyState = this.DONE;
this.dispatchEvent(new Event('readystatechange'));
this.dispatchEvent(new Event('load'));
this.dispatchEvent(new Event('loadend'));
}
}
export function mockXHR({ request: req, response: res, silent = false }) {
if (req instanceof Function) config.request = req;
if (res instanceof Function) config.response = res;
export function mockXHR({ proxy, silent = false }) {
if (proxy instanceof Function) config.request = proxy;

config.silent = silent;
XMLHttpRequest = window.XMLHttpRequest;

// 这个文件中的 XHR

// 代理 fetch 的初始化函数
if (window.XMLHttpRequest && !window.XMLHttpRequest.$mock) {
window.XMLHttpRequest = MockXMLHttpRequest;
[XHR, window.XMLHttpRequest] = [window.XMLHttpRequest, MockXMLHttpRequest];
window.XMLHttpRequest.$mock = true;
if (!silent) console.warn('fetch 已经被代理');
if (!silent) console.warn('XHR 已经被代理');
}
}
22 changes: 9 additions & 13 deletions FakeServer/ajax/fetch/fetch.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,28 @@
const config = { request: null, response: null, silent: false };
const config = { proxy: null, silent: false };
let realFetch;

// 假的 Response 对象
import fakeResponse from './src/response.js';
function makeResponse(data, options) {
return new fakeResponse(data, options);
}

async function fakeFetch(url, options = {}) {
// 只有在 $mock 标记为 true 时才进行代理
if (window.fetch.$mock === true) {
// ! 传入初始参数
const result = config.request(url, options);
const result = await config.proxy(url, options);
if (result) {
// ! 传入创建函数,给与使用者开放权限
const response = config.response(makeResponse);
if (!silent) console.warn('fetch: mock代理中');
return response;
const { body, options = {} } = result;
return new fakeResponse(body, options);
}
}

if (!silent) console.warn('这次 fetch 未使用 mockjs');
if (!config.silent) console.warn('这次 fetch 未使用 mockjs');
return realFetch(url, options);
}
function mockFetch({ request: req, response: res, silent = false }) {
if (req instanceof Function) config.request = req;
if (res instanceof Function) config.response = res;

// 代理出口
export function mockFetch({ proxy, silent = false }) {
if (proxy instanceof Function) config.proxy = proxy;
config.silent = silent;
// 代理 fetch 的初始化函数
if (window.fetch && !window.fetch.$mock) {
Expand All @@ -35,4 +32,3 @@ function mockFetch({ request: req, response: res, silent = false }) {
if (!silent) console.warn('fetch: 已经被代理');
}
}
export { fakeFetch, mockFetch };
Loading

0 comments on commit 3875af7

Please sign in to comment.