用Nodejs写一个Mock Server
一、事情的缘由
最近我们的一个项目,在开发的时候,遇到一个蛋疼的问题。由于需要依赖后端开发提供接口及数据,所以我们都开发机上部署代码,但是有很多个同事同时开发,经常发生代码覆盖的情况。 为了解决这个破问题,我们希望能够在本地进行开发及调试,这时又存在两个蛋疼的问题:
- 接口尚未开发完成
- 接口跨域,不能访问
对于这两个问题,其实也好解决,通过 fiddler
或者 nginx
都可以轻易解决。不过这些方案都不能通用,每个开发都需要自己单独配置,通用性和复用性不强,我们需要更加通用的解决方案。
最后,觉得我们还是需要一个自己的专用 Mock Server。
二、Mock Server
1. 什么是Mock Server?
为了更好的分工合作,让前端能在不依赖后端环境的情况下进行开发,其中一种手段就是为前端开发者提供一个web容器,这个本地环境就是 mock server。
2. Mock Server需要提供哪些能力?
想要前端不依赖后端的环境下正常运行,Mock Server需要下列能力:
- 能渲染模板
- 实现请求路由映射
- 数据接口代理到生产或者测试环境
Mock Server的运行机理:
由于我们这只是一个纯前端项目,所以我们不需要 渲染模板 的功能。我们只需要一个能够 路由转发 和 数据接口 代理的Server。
三、用NodeJs实现一个Mock Server
1. 启动一个Server
通过 http
模块创建一个server。
http.createServer(function(req, res) {
var urlObj = url.parse(req.url.replace('/static/hybrid', '')); //修正fis release 添加的文件路径
var pname = urlObj.pathname;
// 静态资源
if (pname == '/' || /\.\w{2,5}$/.test(pname)) {
findStaticResource(pname, req, res);
} else {
// 判断是json, 还是jsonp
var contentType = 'application/json;charset=UTF-8';
var search = urlObj.search;
var cb = '';
if (search && /[?&](?:callback|cb)=([^&]+)/i.test(search)) {
contentType = 'application/x-javascript';
cb = RegExp.$1;
}
// 重写
if (pname in rewriteList) {
var localPath = path.normalize(config.cwd + '/test' + rewriteList[pname]);
rewriteResource(req, res, localPath, contentType, cb);
} else { // 转发
redirectResource(req, res, localPath, contentType, pname);
}
}
}).listen(config.port);
2. 读取静态文件(html、css、js)
静态资源处理起来还是很简单的。
// 处理静态资源
function loadStaticResource(pathname, req, res) {
var ext = path.extname(pathname);
fs.readFile(pathname, "binary", function(error, file) {
if (error) {
res.writeHead(500, {
"Content-Type": "text/plain"
});
res.end("Server Error:" + error);
} else {
res.writeHead(200, {
"Content-Type": getContentTypeByExt(ext)
});
res.end(file, "binary");
}
});
}
3. 代理数据接口
数据代理,接口重定向,最主要是依赖 http.request
方法。
// 重定向
function redirectResource(req, res, localPath, contentType, pname) {
var host = redirectList['host'] || '', u = {};
if (host) { //通用配置
u = url.parse(host);
}
if (pname in redirectList) { // 特定url配置
u = url.parse(redirectList[pname].host);
};
var options = {
host: u.hostname || config.default.hostname,
port: u.port || config.default.port,
path: req.url,
method: req.method,
};
var xreq = http.request(options, function(_res, _req) {
var body = '';
_res.on('data', function(d) {
body += d;
}).on('end', function() {
res.writeHead(200, {
"Content-Type": contentType
});
res.end(body, "binary");
});
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
xreq.end();
}
四、总结
这个 mock server
功能相对比较简单,主要的工作在于思路。首先必须要能够和我们的开发构建工具 fis
适配,其次在于路由的转发规则及转发配置文件。
部分资料参考: 知乎:你是如何构建 Web 前端 Mock Server 的?