前言
在公司项目vue
开发中,我们用mockjs
这个库来模拟后段数据来开发前面页面,后端开发进度慢的情况下,前后端不能联调,mockjs 简直就是我们福音啊。而且 mockjs 能让我们的项目在每发出一个 xhr 请求的情况下,完整模拟整个页面的操作流程。
思考
mockjs其实可以模拟出很多符合场景的数据,但是二进制文件流就不行了,如我们用axios
发出一个responseType: blob
的请求时,其实是不生效的。但是我们要模拟一个文件数据怎么办?
方法一:node
在本地开发的时候,我们往往是将 mock 的代码放到 webpack(node) 处理的,实际上相当于开启了一个 node 服务,这样的情况下结合 mockjs,可以模拟出任何格式的数据,包括文件(二进制流),模拟二进制流的时候,通常是本地新建一个文件如 PDF 文 件,用 fs
node 模块读取,然后返回到前端。有兴趣的可以了解下 node 的fs
模块
方法二: xhr重写
终于回归正题。理论上我们实现一个拦截 XMLHttpRequest 响应的方法,就能修改响应值,解决 mockjs 无法模拟文件流的问题了
// 定义个请求方法
function request(url, parmas = null, method = 'POST') {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.responseType = 'blob'
xhr.send(parmas)
xhr.onreadystatechange = function () {
const { status, readyState, response } = this;
console.log('状态', status, readyState)
const res = {
data: response,
status
}
if (readyState === 4) {
if (status === 200) {
console.log('response', response)
resolve(res)
} else {
reject(res)
}
}
}
})
}
// 获取本地静态文件
async function getLocalFile(url) {
const res = await request(url, null, 'GET').catch(() => false);
if (res !== false) {
// 成功拿到本地文件
}
}
getLocalFile('./files/001.jpeg'); // url为项目下一个文件路径
将代码复制到一个 html 里面,可以用 vs code 的live server
查看快速开启一个服务来运行 html, 在控制台可以看到文件请求成功了,debugger
的地方也可以查看到 response
的类型是一个Blob
类型
在上面的getLocalFile
方法中,实例化了一个XMLHttpRequest
对象用法发送一个 xhr 请求。要拦截一个请求,不让它发送到后端,可以重写xhr.send
方法, 就可以不让它发送到后端了
(() => {
// 设置 xhr 字段为可写方式,不设置的话,是不能直接用 this.response 的方式来改变响应值
const setWriteKeys = ['status', 'statusText', 'response', 'responseText', 'readyState'];
const open = XMLHttpRequest.prototype.open;
const send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (...agrs) {
open.apply(this, agrs)
};
XMLHttpRequest.prototype.send = function (...agrs) {
setWriteKeys.forEach(key => {
Object.defineProperty(this, key, {
writable: true
})
})
console.log('send', this)
setTimeout(() => {
// 手动改变响应状态和值
this.status = 200
this.readyState = 4; // 原生xhr中该值改变,会触发onreadystatechange方法
this.statusText = 'OK'
this.response = [1, 2, 3, 4];// 这里可以自定义mock的数据
// 手动触发会onreadystatechange方法
this.dispatchEvent(new Event('readystatechange'))
}, 1000);
// send.apply(this, agrs) // 这里这方法就不再调用了,如果调用了,xhr还是会发送到后端
};
})();
// 接前面代码
总结:拦截 XMLHttpRequest 的主要思路是重写 send 的方法,改变响应值,触发状态改变方法