yog-devtools
Version:
提供数据模拟,页面跳转等功能协助前端快速开发。
160 lines (127 loc) • 4.06 kB
JavaScript
/**
* @fileOverview 负责读取 server.conf 转发规则。
*
* 支持 rewrite redirect 两种重定向规则。
*
* ```
* rewrite ^\/testpage /example/page/testpage
*
* rewrite ^\/ajaxHander /test/page/ajaxHandler.js
* rewrite ^\/somejsonfile /test/page/data.json
* ```
*/
var fs = require('fs');
var parseUrl = require('url').parse;
var httpProxy = require('http-proxy');
function escapeHtml(html) {
return String(html)
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
}
function rewriteParser(file) {
var rules = [];
function Ruler(type, reg, to) {
return {
type: type,
reg: reg,
to: to
}
}
if (!Array.isArray(file)) {
file = [file]
};
file.forEach(function(file) {
if (!fs.existsSync(file)) {
return null;
}
var content = fs.readFileSync(file, 'utf-8');
var lines = content.split(/\r\n|\n/);
var rrule = /^(rewrite|redirect|proxy)\s+([^\s]+)\s+([^\s]+)$/i
lines.forEach(function(line) {
var m = rrule.exec(line);
if (!m) {
return;
}
rules.push(new Ruler(m[1].toLowerCase(), new RegExp(m[2], 'i'), m[3]));
});
});
return {
match: function(url) {
var found;
var arr = [
url.path,
url.pathname
];
rules.every(function(ruler) {
arr.every(function(url) {
var m = url.match(ruler.reg);
if (m) {
found = ruler;
found.match = m;
return false;
}
return !found;
});
return !found;
});
return found;
}
}
}
module.exports = function(options) {
var file = options.rewrite_file;
var parser;
// todo cache the file.
function lazyload() {
// 每次都加载好了,server.conf 有可能经常改动。
parser = /*parser || */rewriteParser(file);
}
var proxy = httpProxy.createProxyServer({
changeOrigin: true,
autoRewrite: true
});
proxy.on('error', function(error, req, res) {
var json;
console.log('proxy error', error);
if (!res.headersSent) {
res.writeHead(500, { 'content-type': 'application/json' });
}
json = { error: 'proxy_error', reason: error.message };
res.end(JSON.stringify(json));
});
return function(req, res, next) {
lazyload();
var url = parseUrl(req.url);
var ruler = parser && parser.match(url);
if (ruler) {
var to = ruler.to.replace(/\$(\d+)/g, function(all, index) {
return ruler.match[index] || '';
});
switch (ruler.type) {
case 'rewrite':
req.originalUrl = req.originalUrl || req.url;
req.url = to;
break;
case 'proxy':
var target = parseUrl(to);
req.originalUrl = req.originalUrl || req.url;
req.url = target.path + (target.search ? (url.query ? ('&' + url.query) : '') : url.search || '');
proxy.web(req, res, {
target: target.protocol + '//' + target.host
});
return;
case 'redirect':
default:
res.statusCode = 303
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.setHeader('Location', to)
res.end('Redirecting to <a href="' + escapeHtml(to) + '">' + escapeHtml(to) + '</a>\n')
return;
}
}
next();
};
};