UNPKG

nei

Version:
270 lines (254 loc) 7.53 kB
'use strict' const path = require('path'); const querystring = require("querystring"); const url = require('url'); const _ = require('./util'); // 路径配置 let ROOT = { PK: '', ONLINE: '', ONLINE_SERVER: '', VIEW: '', MOCKTPL: '', MOCKAPI: '', FMPP: '', API_RES_HEADERS: '' }; let VIEW_EXT = ''; // 从nei站点获取数据 function getFromNEISite(type, id, callback, req) { if (!ROOT.ONLINE) { // 不使用在线地址,则不获取数据 return callback(null); } req = req || {}; let params = {path: req.url, type: type, key: ROOT.PK, id: id, method: req.method}; let host = ROOT.ONLINE_SERVER || 'https://nei.netease.com'; let url = `${host}/api/mockdata?` + querystring.stringify(params); // let url = `http://localhost:8082/api/mockdata?` + querystring.stringify(params); console.log(`Mock数据为NEI提供的在线接口: ${url}`); let isHttps = /^https:\/\//i.test(url); // 获取nei站点上的数据 require(isHttps ? 'https' : 'http').get(url, function (res) { let ret = []; res.on('data', function (chunk) { ret.push(chunk.toString()); }); res.on('end', function () { let json = null; try { json = JSON.parse(ret.join('')); } catch (ex) { // ignore } if (json && json.code === 200) { // 成功 if (json.result.error.length) { console.log(`错误: ${json.result.error.map(err => err.message).join(', ')}`); } // 真正的 mock 数据 callback(json.result.json); } else { callback(ret.join('')) } }); }).on('error', function (error) { callback(error.message); }); } // 从 model server 加载注入给页面的模型数据 function getModelFromServer(pagePath, callback, req) { let modelServerOptions = ROOT.MODEL_SERVER; let reqUrl = modelServerOptions.path; if (typeof reqUrl === 'function') { reqUrl = reqUrl({ host: modelServerOptions.host, queries: modelServerOptions.queries, headers: modelServerOptions.headers, path: pagePath }); } // 如果没有设置path,则默认为页面的path if (!reqUrl) { reqUrl = pagePath; } if (!reqUrl.startsWith('http')) { if (!modelServerOptions.host.endsWith('/')) { modelServerOptions.host += '/'; } if (reqUrl.startsWith('/')) { reqUrl = reqUrl.slice(1); } // 是相对地址,加上主机地址 reqUrl = `${modelServerOptions.host}${reqUrl}`; } // 处理查询参数 if (modelServerOptions.queries && Object.keys(modelServerOptions.queries).length) { let qs = querystring.stringify(modelServerOptions.queries); reqUrl += (reqUrl.includes('?') ? `&` : `?`) + qs; } let reqHeaders = {}; // 需要判断有没有 cookie,没有的话,值是 undefined,最后发请求的时候会报错 // 重现方法:本地删除cookie再发请求 if (req.headers.cookie) { reqHeaders.cookie = req.headers.cookie; } // 处理请求头 if (modelServerOptions.headers) { Object.keys(modelServerOptions.headers).forEach(function (headerKey) { reqHeaders[headerKey] = modelServerOptions.headers[headerKey]; }); } let urlParseResult = url.parse(reqUrl); let options = { hostname: urlParseResult.hostname, port: urlParseResult.port, path: urlParseResult.path, headers: reqHeaders, protocol: urlParseResult.protocol }; console.log(`页面 ${pagePath} 的模型请求信息:${JSON.stringify(options)}`); require(urlParseResult.protocol.slice(0,-1)).get(options, function (res) { let ret = []; res.on('data', function (chunk) { ret.push(chunk.toString()); }); res.on('end', function () { let json = {}; try { json = JSON.parse(ret.join('')); console.log(`页面 ${pagePath} 的模型请求返回的 json 数据为:${JSON.stringify(json)}`); } catch (ex) { console.log(`页面 ${pagePath} 的模型请求没有返回 json 数据:${JSON.stringify(ret)}`); } callback(json); }); }).on('error', function (error) { callback(error.message); }); } // 加载数据 function load(type, id, path, callback, req) { let filter = null; try { let file = path + '.js'; filter = require(file); delete require.cache[require.resolve(file)]; } catch (ex) { // ignore } // 如果filter是个json对象 if (filter && (typeof filter !== 'function')) { return callback(filter); } getFromNEISite(type, id, function (json) { if (json == null) { try { let file = path + '.json'; console.log(`Mock数据为本地JSON文件: ${file}`); json = require(file); delete require.cache[require.resolve(file)]; } catch (ex) { // ignore } } if (filter) { json = filter(json, req); } callback(json); }, req); } // api代理 function wrapApi(id, path) { return function (req, res, next) { load(3, id, ROOT.MOCKAPI + path, function (json) { // 不能直接发送数字, 数字会当作响应码 if (typeof json == 'number') { json = json.toString(); } // 设置api响应头 Object.keys(ROOT.API_RES_HEADERS).forEach((key) => { res.set(key, ROOT.API_RES_HEADERS[key]); }); res.send(json); }, req); }; } // 页面代理 function wrapPage(index, list) { return function (req, res, next) { let conf = list[index]; let render = function (json) { if (VIEW_EXT.toLowerCase() === '.ftl') { // ftl 模板, 需要 node fmpp 处理 // 如果不包裹一层,传递的时候 data 上会多出 settings 等字段,见 /node-fmpp/index.js res.render(conf.p + VIEW_EXT, { json: json, fmppConfig: ROOT.FMPP }); } else { res.render(conf.p + VIEW_EXT, json); } } if (ROOT.MODEL_SERVER) { getModelFromServer(req.originalUrl, function (json) { render(json); }, req); } else { load(1, conf.i, ROOT.MOCKTPL + conf.p, function (json) { render(json); }, req); } }; } module.exports = { // 获取设置 getting: function () { return ROOT; }, // 设置接口 setting: function (obj) { ROOT.PK = obj.projectKey; ROOT.ONLINE = obj.online; ROOT.ONLINE_SERVER = obj.onlineServer; ROOT.VIEW = obj.view; ROOT.MOCKTPL = obj.mockTpl; ROOT.MOCKAPI = obj.mockApi; ROOT.CHANGEORIGIN = obj.changeOrigin; ROOT.FMPP = obj.fmpp; ROOT.API_RES_HEADERS = obj.apiResHeaders; ROOT.MODEL_SERVER = obj.modelServer; VIEW_EXT = obj.viewExt; }, // 获取包装过的路由 getRoutes: function (routes) { let retRoutes = {}; Object.keys(routes || {}).forEach(function (routeKey) { let item = routes[routeKey]; if (_.isObject(item)) { if (item.hasOwnProperty('list')) { // 页面 let list = []; item.list.forEach(function (it) { list.push({i: it.id, p: it.path, pagePath: routeKey.split(' ')[1]}); }); retRoutes[routeKey] = { nei: true, data: item, handle: wrapPage(item.index, list) }; } else { // api retRoutes[routeKey] = { nei: true, data: item, handle: wrapApi(item.id, item.path) }; } } else { retRoutes[routeKey] = item; } }); return retRoutes; } };