'use strict';
/**
* 加载静态路由
* @module router/staticRouter
*
* @param {object} opt 启动参数对象
* @param {boolean} opt.staticServerOn 是否开启静态化
* @param {string} opt.staticFileRoot 静态化文件存放根目录
* @param {string} opt.staticPath 静态化接口路径
* @param {object} opt.staticRouterMap 静态化routerMap
* @param {string} opt.dynamicStaticPath 新静态化接口路径
* @param {object} opt.dynamicRouterMap 动态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');
module.exports = function addDynamicRouter(opt) {
// 没开启静态化则直接返回空路由
if (!opt.staticServerOn) {
return router;
}
// 静态文件根目录
let staticRoot = typeof opt.staticFileRoot === 'string' ? opt.staticFileRoot : opt.staticFileRoot.path;
staticRoot = staticRoot.startsWith('/') ? staticRoot : '/' + staticRoot;
/***
* 配置路由
* @param prefix 静态化前缀
* @param routerMap
* @param configFn 配置函数
*/
function setRouter(prefix, routerMap, configFn) {
for (let route of Object.keys(routerMap)) {
let routeConf = routerMap[route];
// routerConf 为字符串形式
if (typeof routeConf === 'string') {
routeConf = {
views: routeConf,
static: routeConf
};
}
// 如果动态路由配置了静态化,则启用静态化
if (!!routeConf.static) {
// 检查每个路由配置的文件夹是否存在
const staticPath = routeConf.static.split('/').filter(n => n !== '');
let pathArr = [staticRoot, ...staticPath];
// 如果以路径以 .html 结尾,就将其作为静态生成文件的文件名,否则将路径全部视为文件夹,文件名默认用 index.html
let fileName = 'index.html';
if (pathArr[pathArr.length-1].endsWith('.html')) {
fileName = pathArr.splice(-1)[0];
}
let filePath = pathArr.join('/');
// 路由path不以'/'开头的则补全
route = route.startsWith('/') ? route : '/' + route;
const staticRouter = require('koa-router')();
staticRouter.post(route, configFn(routeConf, filePath, fileName));
router.use(prefix, staticRouter.routes());
}
}
}
// 原有静态化服务
if (!!opt.staticPath) {
/***
* 静态化处理函数
* @param {object} routeConf 路由配置
* @param {string} filePath, fileName 要生成的文件路径和文件名
*/
const configRouter = (routeConf, filePath, fileName) => function* staticRoutersHandler() {
// log
this.appendLog('routerConf: ' + JSON.stringify(routeConf));
// 生成静态页面
const writeResult = yield utils.writeStaticFile(this, routeConf.views, filePath, fileName, this.request.body);
// log
this.appendLog(`staticMsg: Create ${[filePath, fileName].join('/')} success`);
// 返回结果
this.body = {
code: 0,
msg: `Create ${[filePath, fileName].join('/')} success`
};
};
// 设置路由
setRouter(opt.staticPath, opt.staticRouterMap, configRouter);
}
// 新静态化接口,复用动态路由
if (!!opt.dynamicStaticPath) {
/***
* 静态化处理函数
* @param {object} routeConf 路由配置
* @param {string} filePath, fileName 要生成的文件路径和文件名
*/
const configRouter = (routeConf, filePath, fileName) => function* staticRoutersHandler() {
// log
this.appendLog('routerConf: ' + JSON.stringify(routeConf));
// 取得去除前缀和端口号的host
const host = utils.fixHost(this.host);
let body = {};
// 如果配置中有cgi,则向后端请求数据, 没有配置cgi则不向后端发送数据
if (!!routeConf.cgi) {
// 取得处理过的cgi请求路径,合并query
const cgiUrl = utils.fixCgi(opt.getRequestIP ? yield opt.getRequestIP(this) : this.host, routeConf.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 {
// log
this.appendLog('sendReq: No cgi, do not send request');
}
// 生成静态页面
const writeResult = yield utils.writeStaticFile(this, routeConf.views, filePath, fileName, body);
// log
this.appendLog(`staticMsg: Create ${[filePath, fileName].join('/')} success`);
// 返回结果
this.body = {
code: 0,
msg: `Create ${[filePath, fileName].join('/')} success`
};
};
// 设置路由
setRouter(opt.dynamicStaticPath, opt.dynamicRouterMap, configRouter);
}
return router;
};