'use strict';
/**
* 加载动态路由
* @module router/dynamicRouter
*
* @param {object} opt 启动参数对象
* @param {object} opt.routerMap 动态routerMap
* @param {function} opt.getRequestIP 获取请求地址方法,返回ip或host用于发送后端请求,参数 ctx,注意为 generator 函数
* @param {function} opt.getHeader 处理请求header方法,返回header用于发送后端请求,参数 原header,ctx
* @param {function} opt.getRenderData 处理渲染data方法,返回data用于渲染,参数 原data,ctx
*/
const router = require('koa-router')();
const utils = require('../lib/utils.js');
// routerMap 处理,提取 host 兼容多域名
function parseRouterMap(routerMap) {
let parsedRoutes = {};
for (let k of Object.keys(routerMap)) {
const v = routerMap[k];
let reqPath = '';
let domain = '_';
// path 结尾没有 / 的补全
if (!k.endsWith('/')) {
k = k + '/';
}
let pos = k.indexOf('/');
// 如routerMap中path开以 / 开头,则理解成无配置域名,用默认domain '_' 代替域名
if (pos === 0) {
reqPath = k;
// 如果配置域名,则把域名提取出来
} else {
domain = k.substr(0, pos);
reqPath = k.substr(pos);
// 如果views没有补全域名,则补全域名
if (!!v.views && !v.views.startsWith('/' + domain) && !v.views.startsWith(domain)) {
v.views = domain + v.views;
}
}
// 输出改为 {path: {domain: {views && cgi }}} 的格式
if (!parsedRoutes[reqPath]) {
parsedRoutes[reqPath] = {};
}
parsedRoutes[reqPath][domain] = v;
}
return parsedRoutes;
}
// 路由处理函数
const configRouter = (routeConf, opt) => function* renderRoutersHandler() {
// 取得去除前缀和端口号的host
const host = utils.fixHost(this.host);
// 取得当前请求的views和cgi配置
let currentConf;
// 如果路由映射中有当前域名,按照当前请求域名匹配
if (!!routeConf[host]) {
currentConf = routeConf[host];
// 否则匹配默认配置'_'
} else {
currentConf = routeConf._;
}
// log
this.appendLog('routerConf: ' + JSON.stringify(currentConf));
let body = {};
// 如果配置中有cgi,则向后端请求数据,没有配置cgi则不向后端发送数据
if (currentConf.cgi) {
// 取得处理过的cgi请求路径,合并query
const cgiUrl = utils.fixCgi(opt.getRequestIP ? yield opt.getRequestIP(this) : this.host, currentConf.cgi, this.query, this.params);
// 取得header,根据环境指定后端host,后台根据host来区分后端业务server
const header = opt.getHeader ? opt.getHeader(this.header, this) : this.header;
// log
this.appendLog(`sendReq: ${cgiUrl}`);
// 发送请求
const {result, spendTime} = yield utils.requestCgi(cgiUrl, {
headers: header
});
// log
this.appendLog(`gotRes: ${result.statusCode} ${spendTime}s`);
// 处理结果
body = utils.handleResponce(result, this);
if (!body) {return false;}
// 没有配置cgi则不向后端发送数据
} else {
this.appendLog('sendReq: No cgi, do not send request');
}
// 渲染页面
let html = this.render(currentConf.views, opt.getRenderData ? opt.getRenderData(body, this) : body);
// 输出html
this.body = html;
};
module.exports = function addDynamicRouter(opt) {
let parsedRouterMap = parseRouterMap(opt.routerMap);
for (let route of Object.keys(parsedRouterMap)) {
router.get(route, configRouter(parsedRouterMap[route], opt));
}
return router;
};