除非作为参数

时间:2018-02-04 19:52:31

标签: node.js express

我正在尝试创建映射它自己路由的Node模块。我在下面提供了一个简化的示例(删除了在返回的对象中映射的所有其他函数以及用于简化示例的任何代码)。

我最初的尝试就是这样做:

文件:web-core.js

function initRoutes(app) {
  var express = require('express');  
  var router = express.Router();

  router.get("/basic", function(request, response) {
    response.json({ success: true, path: '/auth/basic' });
  });

  router.get("/oauth2", function(request, response) {
    response.json({ success: false, path: '/auth/oauth2' });
  });

  router.get("/openid", function(request, response) {
    response.json({ success: false, path: '/auth/openid' });
  });

  app.use('/auth', router); // mount the module
}

function init(app) {
  initRoutes(app);                     //-- This does work (but don't like it)
  //initRoutes(require('express')());  //-- This does NOT work!
}

module.exports = (function() {  
  return {    
    init : init
  };  
}());

从我的Node入口点开始:

var express = require('express');
var app = express();

app.use(express.static('public'));

var webAuth = require("./web-auth.js");

webAuth.init(app);  //-- Wish I didn't have to call this!

var listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});

现在,我的主要目标是不必致电webAuth.init(app)(并间接使用initRoutes(require('express')());)。我想让模块不依赖于显式或外部初始化。

但出于某种原因,当我使用initRoutes(require('express')());时,它只是不起作用。它似乎仅在我调用webAuth.init(app)并传入app对象时才有效。

我不确定我在这里缺少什么。我被告知Node将缓存require('express')返回的所有实例,因此从技术上讲,两种方式应该相同并且工作方式相同。

我在网上看到的所有express.Router()示例都提供了简单的用例,而不像我正在尝试的那样“模块化”。

有谁知道它为什么不起作用?

更新:2018.02.04在18:27

我创建了一个包含示例代码的Glitch项目,以便任何人都能理解,可以找到here

似乎总有一些问题或其他问题。缺少文件或某些神秘的“东西”无法正常工作。

根据提供的答案的建议,我决定在外部进行初始化,例如:

var webAuth = require("./web-auth.js");
webAuth.init(app, router);

在我的模块中,我现在有:

function init(app, router) {
  console.log("### Initializing '" + MODULE_NAME + "' module for '" + BASE_PATH + "'");

  initFilters(router);
  initRoutes(app, router);
}

这很有效。当我致电GET /auth/basic时,我的过滤器和/auth/*路线都按预期工作。

但是现在,我开始创建我的第二个模块,这是特定于域的,所以我们会说API应该映射到/domain/*。显然,第二个模块现在应该使用express()express.Router()的新实例,不是吗?否则重复使用相同的方法是没有意义的。

所以当我这样称呼时:

app = express();
router = express.Router();

var webDOMAIN= require("./web-domain.js");
webDOMAIN.init(app, router);

您希望该模块也能在/domain/*路径上工作......但它不会!该死的,使用NodeJS和ExpressJS很令人沮丧。似乎我对这两种技术的经验比我30多年的经历中的任何其他技术都更令人沮丧。

更新:2018.02.06 at 10:59

好的,我终于搞清楚了!我不会在这里发布所有内容,而是会对我自己的问题写一个广泛的答案。

3 个答案:

答案 0 :(得分:2)

同时可能有多个快递应用。所以你需要找到合适的应用来分配路由。由于应用程序无法进行猜测,因此您需要告诉函数使用哪个。

@yue you所述,对require("express")()的调用会创建一个新的快速实例。这意味着,您必须在某个时间点传递正确的实例。

我的建议是摆脱初始化函数,因为它实际上不是构造函数。您可以将初始化部分移动到导出的函数中,这样代码就像快速初始化程序一样工作。这样,您还可以归档您想要的模块化。

网络-auth.js

function init(app) {
  initRoutes(app);
}

module.exports = function(app) {  
  return init(app);
};

然后在您的代码中使用它,如下所示:

require("./web-auth.js")(app);

答案 1 :(得分:1)

require('express')()将创建一个新实例,它不等于之前创建的app。所以你假设Node will cache all instances returned by require('express')不正确。我做了这样的检查,它总是返回假。

function init(app) {
  console.log(app === require('express')()) // Always return false
  initRoutes(app);                     //-- This does work (but don't like it)
  //initRoutes(require('express')());  //-- This does NOT work!
}

答案 2 :(得分:0)

好的,所以ExpressJS基本上有一些重要的事情要理解(我最初并没有完全掌握)。

以下调用通过NodeJS的require()机制缓存:

var express = require('express');

这实际上意味着如果您多次调用上述函数或从其他模块调用,则基本上可以恢复“相同”函数。

接下来是我们获取ExpressJS应用程序上下文的地方。重要的是要理解,对于“每个”电话,你会得到一个新的背景。

var app = express();

这是我出错的地方; (a)没有意识到它是一个不同的上下文,(b)在从express.Router()实例添加路由时不重用主要上下文。最初我试图为每个模块创建一个新的上下文,这不是必需的。我稍后会解释一下。

最后,每次跟随调用都会创建一个新的“路由器”实例,您可以在其中映射路线。

var router = express.Router();

您将需要为您创建的每个模块创建新路线。如上所述,您将每个模块路由添加到“主”应用程序上下文中,如下所示:

app.use(BASE_PATH, router); 

因此,您基本上“共享”app的单个实例,但为每个模块创建一个新的router实例。由于我创建了一个“应用”上下文并向其添加了“路由器”,因此只有最后一个工作正常。

这是我的NodeJS + ExpressJS代码,其中包含一些示例模块:

文件 server.js

var express = require('express');
var app = express();
var router = express.Router();

app.use(express.static('public'));

//------------------------------------------------------------
// Modules here...
//------------------------------------------------------------

var webAuth = require("./web-auth.js");
webAuth.init(app);

var webXYZ = require("./web-xyz.js");
webXYZ.init(app);

var webABC = require("./web-abc.js");
webABC.init(app);

//------------------------------------------------------------

// listen for requests :)
var listener = app.listen(process.env.PORT, function () {
  console.log('Your app is listening on port ' + listener.address().port);
});

档案 web-abc.js

// ----------------------------------------------------------------------------
// Private Properties
// ----------------------------------------------------------------------------

var one = 1;
var two = 2;
var foo = "foo";
var bar = "bar";

var MODULE_NAME = 'web-abc';
var BASE_PATH = '/abc';


// ----------------------------------------------------------------------------
// Private API's
// ----------------------------------------------------------------------------

/**
 * Route middleware that will happen on every request
 */
function initFilters(router) {
  console.log("### Initializing filter!!!");

  router.use(function(req, res, next) {
      // log each request to the console
      console.log("Filter 1: " + req.method, BASE_PATH + req.url);

      // continue doing what we were doing and go to the route
      next(); 
  });

  router.use(function(req, res, next) {
      // log each request to the console
      console.log("Filter 2: " + req.method, BASE_PATH + req.url);

      // continue doing what we were doing and go to the route
      next(); 
  });
}

function initRoutes(app, router) {
  console.log("### Initializing routes!!!");

  router.get("/foo", function(request, response) {
    console.log("Endpoint: " + BASE_PATH + "/foo");
    response.json({ success: true, path: BASE_PATH + '/foo' });
  });

  router.get("/bar", function(request, response) {
    console.log("Endpoint: " + BASE_PATH + "/bar");
    response.json({ success: false, path: BASE_PATH + '/bar' });
  });

  app.use(BASE_PATH, router); // mount the module
}

function getFoo() {
  return foo;
}

function setFoo(value) {
  foo = value;
}

function getBar() {
  return bar;
}

function setBar(value) {
  bar = value;
}

function init(app) {
  console.log("### -------------------------------------------------------------");
  console.log("### Initializing '" + MODULE_NAME + "' module, for path '" + BASE_PATH + "'");

  var express = require('express');
  var router = express.Router();

  initFilters(router);
  initRoutes(app, router);
}

// ----------------------------------------------------------------------------
// Module Export
// ----------------------------------------------------------------------------

module.exports = (function() {

  return {

    // ------------------------------------------------------------------------
    // Public Properties
    // ------------------------------------------------------------------------

    pub1: 8,
    pub2: 9,

    // ------------------------------------------------------------------------
    // Public API's
    // ------------------------------------------------------------------------

    getFoo  : getFoo,
    setFoo  : setFoo,

    getBar  : getBar,
    setBar  : setBar,

    init    : init
  };

}());

档案 web-xyz.js

// ----------------------------------------------------------------------------
// Private Properties
// ----------------------------------------------------------------------------

var one = 1;
var two = 2;
var foo = "foo";
var bar = "bar";

var MODULE_NAME = 'web-xyz';
var BASE_PATH = '/xyz';


// ----------------------------------------------------------------------------
// Private API's
// ----------------------------------------------------------------------------

/**
 * Route middleware that will happen on every request
 */
function initFilters(router) {
  console.log("### Initializing filter!!!");

  router.use(function(req, res, next) {
      // log each request to the console
      console.log("Filter 1: " + req.method, BASE_PATH + req.url);

      // continue doing what we were doing and go to the route
      next(); 
  });

  router.use(function(req, res, next) {
      // log each request to the console
      console.log("Filter 2: " + req.method, BASE_PATH + req.url);

      // continue doing what we were doing and go to the route
      next(); 
  });
}

function initRoutes(app, router) {
  console.log("### Initializing routes!!!");

  router.get("/foo", function(request, response) {
    console.log("Endpoint: " + BASE_PATH + "/foo");
    response.json({ success: true, path: BASE_PATH + '/foo' });
  });

  router.get("/bar", function(request, response) {
    console.log("Endpoint: " + BASE_PATH + "/bar");
    response.json({ success: false, path: BASE_PATH + '/bar' });
  });

  app.use(BASE_PATH, router); // mount the module
}

function getFoo() {
  return foo;
}

function setFoo(value) {
  foo = value;
}

function getBar() {
  return bar;
}

function setBar(value) {
  bar = value;
}

function init(app) {
  console.log("### -------------------------------------------------------------");
  console.log("### Initializing '" + MODULE_NAME + "' module, for path '" + BASE_PATH + "'");

  var express = require('express');
  var router = express.Router();

  initFilters(router);
  initRoutes(app, router);
}

// ----------------------------------------------------------------------------
// Module Export
// ----------------------------------------------------------------------------

module.exports = (function() {

  return {

    // ------------------------------------------------------------------------
    // Public Properties
    // ------------------------------------------------------------------------

    pub1: 8,
    pub2: 9,

    // ------------------------------------------------------------------------
    // Public API's
    // ------------------------------------------------------------------------

    getFoo  : getFoo,
    setFoo  : setFoo,

    getBar  : getBar,
    setBar  : setBar,

    init    : init
  };

}());

档案 web-auth.js

// ----------------------------------------------------------------------------
// Module Dependencies
// ----------------------------------------------------------------------------

//var mongoose = require('mongoose');
//var Schema = mongoose.Schema;

// ----------------------------------------------------------------------------
// Private Properties
// ----------------------------------------------------------------------------

var one = 1;
var two = 2;
var foo = "foo";
var bar = "bar";

var MODULE_NAME = 'web-auth';
var BASE_PATH = '/auth';


// ----------------------------------------------------------------------------
// Private API's
// ----------------------------------------------------------------------------

/**
 * Route middleware that will happen on every request
 */
function initFilters(router) {
  console.log("### Initializing filter!!!");

  router.use(function(req, res, next) {
      // log each request to the console
      console.log("Filter 1: " + req.method, BASE_PATH + req.url);

      // continue doing what we were doing and go to the route
      next(); 
  });

  router.use(function(req, res, next) {
      // log each request to the console
      console.log("Filter 2: " + req.method, BASE_PATH + req.url);

      // continue doing what we were doing and go to the route
      next(); 
  });
}

function initRoutes(app, router) {
  console.log("### Initializing routes!!!");

  router.get("/basic", function(request, response) {
    console.log("Endpoint: " + BASE_PATH + "/basic");
    response.json({ success: true, path: BASE_PATH + '/basic' });
  });

  router.get("/oauth2", function(request, response) {
    console.log("Endpoint: " + BASE_PATH + "/oauth2");
    response.json({ success: false, path: BASE_PATH + '/oauth2' });
  });

  router.get("/openid", function(request, response) {
    console.log("Endpoint: " + BASE_PATH + "/openid");
    response.json({ success: false, path: BASE_PATH + '/openid' });
  });

  app.use(BASE_PATH, router); // mount the module
}

function getPub1() {
  return this.pub1;
}

function getPub2() {
  return this.pub2;
}

function getPub3() {
  return this.pub3;
}

function getOne() {
  return one;
}

function getTwo() {
  return two;
}

function getFoo() {
  return foo;
}

function getBar() {
  return bar;
}

function setBar(value) {
  bar = value;
}

function init(app) {
  console.log("### -------------------------------------------------------------");
  console.log("### Initializing '" + MODULE_NAME + "' module, for path '" + BASE_PATH + "'");

  var express = require('express');
  var router = express.Router();

  initFilters(router);
  initRoutes(app, router);
}


// ----------------------------------------------------------------------------
// Model Definition
// ----------------------------------------------------------------------------

// var templateSchema = new Schema({
//   title : String,
//   author : String,
//   body : String,
//   comments : [{ body: String, date: Date }],
//   date : { type: Date, default: Date.now },
//   hidden : Boolean,
//   tags: { type: [String], index: true }, // field level index
//   meta : {
//     votes : Number,
//     favs :  Number
//   }
// });


// ----------------------------------------------------------------------------
// Module Export
// ----------------------------------------------------------------------------

module.exports = (function() {

  return {

    // ------------------------------------------------------------------------
    // Public Properties
    // ------------------------------------------------------------------------

    pub1: 8,
    pub2: 9,

    // ------------------------------------------------------------------------
    // Public API's
    // ------------------------------------------------------------------------

    getPub1 : getPub1,
    getPub2 : getPub2,
    getPub3 : getPub3,
    getOne  : getOne,
    getTwo  : getTwo,
    getFoo  : getFoo,

    getBar  : getBar,
    setBar  : setBar,

    init    : init
  };

}());

通过上面的示例,您基本上启动了一个NodeJS服务器,其中三个不同的模块导出他们自己的Web API路由(端点)和过滤器。

补充信息

ExpressJS人员决定在module.exports变量上返回一个函数。因此我选择导出一个映射方法的对象。此对象还具有公共属性(在外部看到)和一些无法从外部访问的私有属性。

您可以使模块自包含。在我的例子中,'web-auth.js'模块绑定所有可能的身份验证端点(路由),并具有处理它们的验证和域逻辑。它接收SessionID或ClientID和SecretKey组合来验证用户。它使用Mongoose存储SessionID并管理它们等。