以geo项目代码以及krakenjs对info/paypalize做一次分析(paypal)

第一步:生成server主入口

  • 这边startserver主函数,.prepare是nextjs提供的后端渲染套件,返回一个promise对象,then中的逻辑不多说,主要是加载各类中间层,核心内容是server.use(kraken(paypalize(options)))
const config = require('./config')

const options = {
  onconfig: function (config, next) {
    next(null, config)
  }
}

function startServer(server) {
  return app
    .prepare()
    .then(async () => {
      // Hide server info for security.
      server.disable('x-powered-by')
      server.set('trust proxy', true)

      server.use(cookieParser())
      server.use(rewrite(`${getAppBaseUrl()}/*`, '/$1'))
      server.use(kraken(paypalize(options)))
      server.use(express.static(path.join(__dirname, '../public')))

      await nextI18next.initPromise

      const port = process.env.PORT
      return server.listen(port, (err) => {
        if (err) throw err
        // eslint-disable-next-line
        console.log(`>>> Ready on http://localhost:${port}`)
      })
    })
    .catch((error) => {
      logger.error('Exit with 500', error)
      process.exit(1)
    })
}

第二步:建立kraken-paypalize中间件

  • 原本krakenjs可以接受onchange这个钩子函数,如下所示 , onchange可以挨个读取config.js(默认的话)中的配置进行迭代,如果当前配置符合业务需求则调用next(null, config)开始下一项配置
var kraken = require('kraken-js'),
    app = require('express')(),
    options = {
        onconfig: function (config, next) {
            config.get('view engines:js:renderer:arguments').push(app);

            next(null, config);
        }
        /* more options are documented in the README */
    },
    port = process.env.PORT || 8000;


app.use(kraken(options));
  • 这边paypal重写了这边的config参数,加入一些业务中的配置所以采用了paypalize(options)

第三步:paypalize中间件主体 (index.js)

  • 定义全局捕获node错误的两个函数,这里不做赘述,主要是为了规范错误输出以及输出log
process.on('unhandledRejection', UncaughtHandlers.rejection);
process.on('uncaughtException', UncaughtHandlers.uncaught);
  • 初始化一些参数变量,例如basedir,protocols等,其实这些配置都是和kraken原来的配置参数同名的,方便之后覆盖
    const { basedir = Path.dirname(Caller()), protocols = {}, startupHeaders = {} } = defaults;
    const { vault = {}, listenBeforeBootstrap = false } = Shush(Path.join(basedir, 'config/config.json')); // Shush will throw on missing file.
    const appname = AppName(basedir);

    if (process.env.DEPLOY_ENV) {
        vault.name = appname;
        vault.env = Environment._env();
    }
  • 准备覆盖kraken原有的option,这边的核心内容是为protocols新增两个解析器vault()以及keymaker(),其他其实要么{}要么写死的
    const overrides = {
        vault,
        basedir,
        listenBeforeBootstrap,
        protocols: Object.assign({}, protocols, {
            vault: VaultHandler(vault)
        }, {
            keymaker: KeymakerHandler({ appname }) //appname is needed for DEV/QA
        }),
        startupHeaders: Object.assign({
            'X-SLR-RETRY': 'Server is starting.'
        }, startupHeaders)
    };

    const options = Object.assign({}, defaults, overrides);
  • 覆盖kraken option中的ttl部分,不做赘述,paypal这边注释写了为啥
//If `maxTTL` is not zero, Use ReDNS to cache dns lookups with a TTL
//Set a 1 minute max TTL value by default.
if (options.maxTTL !== 0 && options.dnsCache) {
        const redns = new ReDNS({
            maxTTL: options.maxTTL || 60
        });
        Dns.lookup = redns.lookup.bind(redns);
    }
  • 覆盖kraken option中的onKrakenMount参数,其实主要是为了修改app实例的listen方法来改变监听行为,Server这个对象是paypal事先定义好的,这边这个函数也就起到了切换的作用
const onKrakenMountFunc = options.onKrakenMount;
    options.onKrakenMount = function onKrakenMount (app, _options) {
        // execute onkrakenmount function if any.
        onKrakenMountFunc && onKrakenMountFunc(app, _options);

        if(!_options.listenBeforeBootstrap) {
           overrideListen(app);
        }

    }

const overrideListen = (app) => {
    app.listen = function listen() {
        const server = new Server(app);
        return server.listen.apply(server, arguments);
    };
};

  • 最后一步去复写onconfig函数,由于原先kraken中onconfig函数是一个迭代器,所以这边也是一样的,复写函数一样需要返回一个带next的函数迭代器
options.onconfig = WrapOnConfig(Immutable.Map(options));

第四步:通过WrapOnConfig去加载业务上所需的一些中间层

  • 这边的核心代码其实没多少,概括下就是三步走,第一将onconfig包装成promise对象,第二stepbystep去循环包裹相应的中间层,第三分别记录包裹开始时间和结束时间输出日志
    const original = options.get('onconfig') && promisify(options.get('onconfig'));
    const steps = Steps(options);
   ...  
  try {
            for (const step of steps) {
                const stepStart = process.hrtime();

                nconfig = await step(nconfig);

                if (step.name) {
                    benchmark[step.name] = toMilli(process.hrtime(stepStart));
                }
            }

            if (original) {
                const onconfigStart = process.hrtime();
                nconfig = await original(nconfig);
                benchmark['onconfig'] = toMilli(process.hrtime(onconfigStart));
            }

            next(null, nconfig);
        }

第五步:开始加载中间层(以default为例子)

  • 这边注意,所有的中间层的输入输出一定是 参数config=》async function(){return config}的形式,default中间层涉及的业务逻辑并不多,主要功能是将appConfig(kraken也就是项目中配置的config)和paypalizeConfig(paypalize中间层中的config)合并在一起(merge),以及将appProtocols(本来kraken自带的一些解析器)和paypalizeProtocols(主要是vault和keymaker这两个的解析器)合并在一起,合并用的npmpackage为confit
    const basedir = options.get('basedir');
    const configdir = options.get('configdir') || Path.join(__dirname, '../..');
    const protocolOverrides = options.get('protocols');
    const appbasedir = Path.resolve(basedir);
    const appProtocols = Protocols(appbasedir, protocolOverrides);
    const paypalizebasedir = Path.resolve(configdir);
    const paypalizeProtocols = Protocols(paypalizebasedir, protocolOverrides);
    .....
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容