官网介绍
模拟随机数据,拦截ajax
源码
由于VUE的前后端开发耦合分离,所以前端拿到接口文档后,就可以进行开发。
但是开发过程的时候,前端如果能够有一个测试请求数据的后台的话,那可以大大降低后面的前后端对接的工作量。
如果让后台开发者去做,无疑是给他们增加工作量,一般都是不愿意的。即使愿意也会影响感情。那这些工作只能让前端开发人员自己去实现一个。
全靠nodejs这个工具的出现,让前端开发人员实现一个简单的服务器变成一个分分钟就可以解决的事情。
这里结合mockjs+expressjs
开发一个模拟数据请求的服务器后台,并且添加自动化处理等,让这个后台使用变得更加简单,好用。
准备工作
安装express mockjs
npm install --save-dev express mockjs
express这个框架使用起来非常方便。
const express = require("express");
const app = express();
// body-parser是express已经下载好的
const bodyParser = require("body-parser");
const multipart = require("connect-multiparty");
const multipartMiddleware = multipart();
// 这个是配置跨域请求
const cors = require('./cors.js')
// 跨域配置
app.use(cors);//使用跨域中间件
//引入mockjs
const Mock = require("mockjs");
// 端口配置
const port = 9001;
// 入口函数
async function init(){
/**
* 异步导入 配置
*/
const config = await require("./config");
// 路由 请求体 设置
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
/**
* 文件是否缺失或者路径出错
*/
if (config.succ === 'ok') {
let data = config.data
// 将请求路由 传递给 mockjs
connectMock(data)
} else {
// mock 语法有错
throw new Error(config.err)
}
/**
* 运行 server时可以指定端口
*/
process.argv.forEach((arg, index, arr) => {
if (arg === "--port") {
port = arr[index + 1] || 9001;
return false;
}
});
app.listen(port, () => {
console.log("Mock Server listening on http://localhost:" + port);
})
}
multipart
是处理文件上传,直接配置即可。
connectMock(data)
是将请求体里的数据传递给路由配置进行处理,并且连接mockjs
URL 说明 是否允许通信
http://www.domain.com/a.js
http://www.domain.com/b.js 同一域名,不同文件或路径 允许
http://www.domain.com/lab/c.js
http://www.domain.com:8000/a.js
http://www.domain.com/b.js 同一域名,不同端口 不允许
http://www.domain.com/a.js
https://www.domain.com/b.js 同一域名,不同协议 不允许
http://www.domain.com/a.js
http://192.168.4.12/b.js 域名和域名对应相同ip 不允许
http://www.domain.com/a.js
http://x.domain.com/b.js 主域相同,子域不同 不允许
http://domain.com/c.js
http://www.domain1.com/a.js
http://www.domain2.com/b.js 不同域名 不允许
不同端口也是不能进行跨域的
所以需要配置下跨域。
由于是本地服务器,所以配置起来只需配置返回的响应头即可。
cors.js
//设置允许跨域访问该服务. cors.js
module.exports = function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:9000');// 请求地址
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');// 跨域运行的方法
res.header('Access-Control-Allow-Headers', 'Content-Type,lang');// 跨域运行携带的请求header
res.header('Access-Control-Allow-Credentials', 'true');// 客户端是否显示响应头的header
res.header('Access-Control-Allow-Cookie', 'true');//是否允许携带cookie
next();
};
/**
* 连接config和mock 识别mock语法 并且配置express
* @param {Array} data config的配置数据
*/
function connectMock(data) {
data.forEach(({ method, url, data }) => {
if (method === "get") {
app.get(url, (req, res) => {
res.json(mock(data, req.query));
});
} else if (method === "post") {
app.post(url, multipartMiddleware, (req, res) => {
res.json(mock(data, req.body));
});
} else if (method === "jsonp") {
app.get(url, (req, res) => {
const query = req.query;
const mockData = JSON.stringify(mock(data, req.query));
const callback =
"typeof " +
query.callback +
' === "function" && ' +
query.callback +
"(" +
mockData +
")";
res.send(callback);
});
}
});
}
我们分析connectMock
app.use是配置请求的路由设置。
我们数据格式是这样的:
module.exports = [
{
url: "/api/getUserInfo",
name: 'getUserInfo',
path: 'getUserInfo',// 文件地址
method: 'get'
}
]
我们看到connectMock中使用了导入的mock(data,req.body)
其中data就是我们需要mock返回的数据,我们可以使用mockjs文档提供的语法,获取到随机的数据。
如我们传入的data是这样的一个json对象
{
"number|1-100": 100
}
请求之后,返回的就是1-100之间的数字
这里的数据格式参考mockjs官网文档。
我们将路由配置信息分离到一个文件api.js
,将需要返回数据的格式分离到各自的文件路由名字的路由文件中。
就是如果路由文件名字为a
,则其数据文件保存到data/a.js
上。
文件目录如下:
我们使用的时候只需要关系api.js与对应的文件即可。
我们将路由配置信息用另外一个文件保存,但是配置好api之后每次都需要新建文件与写好module.exports={}
等一下重复的语句。
为了能够自动化处理这些重复的工作,我们可以在server.js
配置路由前,去检测是否存在文件,并自动创建文件。
新建一个config.js
// 路由路径 请求方法等信息
const api = require('./apis/api.js')
const path = require('path')
// 公用方法
const utils = require('./utils.js')
/**
* @param {array} config
* 这里自动创建不存在的文件
*/
function handelConfig(config) {
let arr = [], length = config.length
/**
* 做一个闭包 只有全部文件创建结束 才返回数据
*/
return new Promise(async (res, rej) => {
for (let value of config) {
let filePath = path.resolve(__dirname, `./data/${value.path}.js`)
let fileStatus = await utils.fileIsExist(filePath)
if ('ok' === fileStatus) {
arr.push({
method: value.method,
url: value.url,
data: require(`./data/${value.path}.js`)
})
length--
if (length <= 0) {
res({
succ: 'ok',
data: arr
})
}
} else {
let createFile = await utils.fileCreateAndWrite(filePath, {
emitClose: false,
autoClose: false
})
console.log(createFile)
// 创建文件成功
if ('ok' === createFile) {
arr.push({
method: value.method,
url: value.url,
data: require(`./data/${value.path}.js`)
})
length--
if (length <= 0) {
res({
succ: 'ok',
data: arr
})
}
} else {
// 创建文件失败
rej('file create fail')
}
}
}
})
}
module.exports = handelConfig(api);
utils.js
存放一些操作文件的方法
const path = require('path')
const fs = require('fs')
module.exports = {
/**
* 查看是否存在文件
* @function promise
* @param {str} path 路径
*/
fileIsExist(path) {
return new Promise((res) => {
if (fs.existsSync(path)) {
res('ok')
} else {
res('file is no exist')
}
})
},
/**
* 创建文件并写入
* @function promise
* @param {str} path 文件路径
* @param {obj} option 默认值为{} writeStream的option的配置
* @param {str} inString 有默认值 写入的内容
*/
fileCreateAndWrite(path, option = {}, inString = 'module.exports={succ:"ok",result:{Message:"file has init"}}') {
let writeStream = fs.createWriteStream(path, option)
console.log('调用fileCreateAndWrite')
return new Promise(async (res, rej) => {
await writeStream.write(inString)
writeStream.close()
writeStream.on('close', () => {
res('ok')
console.log('探探路')
})
writeStream.on('error', (err) => { rej(err); });
})
}
}
全部代码附上,相信都是能够非常简单能够看懂。
完整的server.js
const express = require("express");
const bodyParser = require("body-parser");
const multipart = require("connect-multiparty");
const cors = require('./cors.js')
const app = express();
const multipartMiddleware = multipart();
const Mock = require("mockjs");
// 端口配置
const port = 9001;
// 跨域配置
app.use(cors);//使用跨域中间件
/**
* 识别mock数据 进行返回
* 具体格式 参考http://mockjs.com/examples.html
* @param {obj|fun} data 对象的话直接返回数据 如果是函数 则要进行进一步处理
* @param {obj} params 这个是mock的语法的参数
*/
const mock = (data, params) => {
if (Object.prototype.toString.call(data) === "[object Object]") {
return Mock.mock(data);
} else if (typeof data === "function") {
return Mock.mock(data(params));
} else {
return "error: data shold be an object or a function.";
}
};
/**
* 初始化
*/
async function init() {
/**
* 异步导入 配置
*/
const config = await require("./config");
// 路由 请求体 设置
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
/**
* 文件是否缺失或者路径出错
*/
if (config.succ === 'ok') {
let data = config.data
connectMock(data)
} else {
// mock 语法有错
throw new Error(config.err)
}
/**
* 运行 server时可以指定端口
*/
process.argv.forEach((arg, index, arr) => {
if (arg === "--port") {
port = arr[index + 1] || 9001;
return false;
}
});
app.listen(port, () => {
console.log("Mock Server listening on http://localhost:" + port);
})
}
/**
* 连接config和mock 识别mock语法 并且配置express
* @param {Array} data config的配置数据
*/
function connectMock(data) {
data.forEach(({ method, url, data }) => {
if (method === "get") {
app.get(url, (req, res) => {
res.json(mock(data, req.query));
});
} else if (method === "post") {
app.post(url, multipartMiddleware, (req, res) => {
res.json(mock(data, req.body));
});
} else if (method === "jsonp") {
app.get(url, (req, res) => {
const query = req.query;
const mockData = JSON.stringify(mock(data, req.query));
const callback =
"typeof " +
query.callback +
' === "function" && ' +
query.callback +
"(" +
mockData +
")";
res.send(callback);
});
}
});
}
module.exports = init()
使用mockjs非常简单,只需要搭建服务器->配置路由->传入mockjs数据格式->服务器返回处理后的数据-》前端就可以完成接受。
比较建议搭建自己亲自去搭一个,遇到一些可以自动化处理的事情,多去尝试下,未来前端肯定不会再重复性地简单搭页面了。
腾讯和阿里这些大厂都在做根据ui图自动生成页面,大大减低了开发成本。这也看到了前端未来的趋势:跨平台,自动化,低门槛等。