xiongwilee / Gracejs

A Nodejs BFF framework, build with koa2(基于koa2的标准前后端分离框架)
https://grace.wilee.me
MIT License
1.39k stars 238 forks source link

ctx对象上没有mongo方法? #23

Open varyuanye opened 7 years ago

varyuanye commented 7 years ago
  return async function mongo(ctx, next) {
        if (ctx.mongo) return await next();
        Object.assign(ctx, {
            mongo: function(mod, data) {
                if (!Model || !Model[mod]) {
                    debug("can't find model : " + mod);
                    return;
                }
                return (new Model[mod](data));
            },
            mongoMap: function(list) {
                return Promise.all(list.map(mongoExecMap));

                function mongoExecMap(opt) {
                    let arg = opt.arg || [];
                    let model = opt.model;
                    let fun = opt.fun;
                    let execfun = (fun.constructor.name === 'GeneratorFunction') ? co.wrap(fun) : fun;
                    let execRes = execfun.apply(model, arg);
                    return execRes.exec ? execRes.exec() : execRes;
                }
            }
        })
        await next();

我在中间添加了wechat的中间件作用自动拉取access_token,以及自动拉取用户列表数据

  1. 文档中是在controller中使用this调用,我希望在wechat中间件中链接mongo(在每天定点同步关注用户列表)上面这个代码我console.log(ctx.mongo)结果是undefined,如何在中间件中调用mongo
  2. 这个router这个中间件资质愚钝,实在是不太懂,, ctx和this实在是搞不明白.官方文档不是都可以用么但是这里的ctx和this是有区别的,就上面这个mongo的中间件.我看到object.assign已经将mongo合并到ctx上了..但是没什么console ctx还是没有
xiongwilee commented 7 years ago

代码debug下看看,确定Obejct.assign这一句执行了吗?

src/app.js里有一个判断,如果你不配置数据库连接,是不会注入这个中间件的:

  // 如果配置了mongo.api则连接数据库
  config.mongo.api[appName] && vapp.use(Middles.mongo(vapp, {
    root: appPath + '/model/mongo',
    connect: config.mongo.api[appName]
  }))
varyuanye commented 7 years ago
module.exports = function graceMongo(app, options) {

    const root = options.root;
    const connect = options.connect;
    // 如果root不存在则直接跳过
    if (!fs.existsSync(root)) {
        debug('error : can\'t find mongo path ' + root);
        return async function mongo(ctx, next) { await next() }
    }

    // 创建数据库连接
    let db = mongoose.createConnection(connect);
    db.on('error', function(err) {
        debug(`error: connect ${connect} ${err}`);
    });
    db.once('open', function() {
        debug(`connect ${connect} success!`);
    });

    let Schema = {},
        Model = {};
    _ls(root).forEach(function(filePath) {
        if (!/.js$/.test(filePath)) {
            return;
        }

        let mod = require(filePath);
        // 创建schema
        let _schema = new mongoose.Schema(mod.schema[0], mod.schema[1]);
        _schema.methods = mod.methods;

        // 发布为Model
        let _model = db.model(mod.model, _schema);
        Schema[mod.model] = _schema;
        Model[mod.model] = _model;
    });
    console.log('数据库链接创建成功')
    console.log('appMongo'+root)
    console.log('数据库链接路径'+connect)

    return async function mongo(ctx, next) {
        if (ctx.mongo) return await next();
        console.log('mongo开始挂载')
        Object.assign(ctx, {
            /**
             * mongo
             * @return {Object} 返回一个Entity对象
             */
            mongo: function(mod, data) {
                if (!Model || !Model[mod]) {
                    debug("can't find model : " + mod);
                    return;
                }
                return (new Model[mod](data));
            },
            /**
             * mongoMap
             * @param {Array} list mongo请求列表
             *        {Object}    list[].model 模型
             *        {Array}     list[].arg 参数
             *        {Function}  list[].fun 模型方法
             */
            mongoMap: function(list) {
                return Promise.all(list.map(mongoExecMap));

                function mongoExecMap(opt) {
                    let arg = opt.arg || [];
                    let model = opt.model;
                    let fun = opt.fun;

                    // 如果fun是generator则转成Promise
                    let execfun = (fun.constructor.name === 'GeneratorFunction') ? co.wrap(fun) : fun;

                    // fun有可能不是Promise, 利用mongoose中的exec()方法转为promise
                    // 参考:http://mongoosejs.com/docs/promises.html
                    let execRes = execfun.apply(model, arg);
                    return execRes.exec ? execRes.exec() : execRes;
                }
            }
        })
        console.log('mongo挂载完成')
        await next();
    };
}

已经在中间console一次数据,结果分别是这样的

数据库链接创建成功
appMongoC:\demo_repository\koa-grace\app\wechat/model/mongo
数据库链接路径mongodb://localhost:12345/wechat
C:\demo_repository\koa-grace\middleware\wechat\token\access_token.json
wechat组件进入页面
数据库链接创建成功
appMongoC:\demo_repository\koa-grace\app\blog/model/mongo
数据库链接路径mongodb://localhost:12345/blog
数据库链接创建成功
appMongoC:\demo_repository\koa-grace\app\blog/model/mongo
数据库链接路径mongodb://localhost:12345/blog
mongo开始挂载
mongo挂载完成
[Function: mongo]

可以看到mongo似乎是成功挂载上了 但是当第二次测试的时候就变成

mongo开始挂载
mongo挂载完成
undefined

挂载失败.但是if (ctx.mongo) return await next();当ctx.mongo是undefined的时候应该是继续挂载到ctx上啊..然而并没有...

xiongwilee commented 7 years ago

但是当第二次测试的时候就变成

是说,第一次刷新能在控制器里读到this.mongo方法,第二次刷新就看不到了?