如何仅将参数传递给需要它的中间件?

时间:2018-07-02 18:33:54

标签: javascript node.js express middleware

我有一个Express应用程序,我正在尝试将所有中间件放在其自己的文件中。一些中间件功能需要db对象,而某些则不需要。

对于不需要db对象的函数来说,这非常简单,但是鉴于下面的代码结构,如何在db中引用doesNotNeedDbParam对象,因为它已经具有参数reqresnext

somefile.js:

const router = express.Router()
const doesNotNeedDbParam = require('./middleware')().doesNotNeedDbParam

function foo () {
  // Currently I have to call require and pass in the db object here b/c 
  // it's not set when requiring the function doesNotNeedDbParam
  router.use(require('./middleware')(db).needsDbParam // <-- Is there a better way to do this so that I can require the file above and pass the db object in when it's set?
}

// Setup db object here
foo()

middleware.js

function doesNotNeedDbParam (req, res, next) {
  ...
}

function needsDbParam (req, res, next) {
  // Where do I reference the db variable?
}

module.exports = (db) => {
  return {
    doesNotNeedDbParam: doesNotNeedDbParam,
    needsDbParam: needsDbParam
  }
}

2 个答案:

答案 0 :(得分:8)

功能方法

我认为,一个不错的结构是尝试currying您的中间件。这种模式是由body-parser之类的中间件实践的,而Express serve-static在内部则是一种实践。这样,您只需要一次,并在需要的地方传递db,而在不需要的地方传递:{p>

// Instead of declaring each function directly as a middleware function,
// we declare them as a function that returns a middleware function
function doesNotNeedDbParam () {
  return function (req, res, next) {
    …
  }
}

function needsDbParam (db) {
  return function (req, res, next) {
    // You can use db here along with req, res, next
  }
}

// No need to export a function now
module.exports = {
  doesNotNeedDbParam,
  needDbParam,
};

然后,只需:

const middleware = require('./middleware');
…
router.use(middleware.doesNotNeedDbParam()); // Since this doesn't need anything, no argument
router.use(middleware.needsDbParam(db)); // You can pass db here now

如果您熟悉ES6 +语法,可以凝结为:

const doesNotNeedDbParam = () => (req, res, next) => {
  …
}

const needsDbParam = (db) => (req, res, next) => {
  // Use db here
}
// Export object here...

然后:

const { doesNotNeedDbParam, needsDbParam } = require('./middleware');
… 
router.use(doesNotNeedDbParam());
router.use(needsDbParam(db));

附加方法

还有另一种方法,可以将属性附加到req对象 一次。这样一来,您就不必在每次需要时都重新输入db。许多其他软件包也使用这种策略。它是这样的:

function attachDb (db) { // Still use curry approach here since we want db
  return function (req, res, next) {
    // Attaches the specified db to req directly
    req.db = db;
  }
}

function needsDbParam (req, res, next) { // No need for currying
  // Now use req.db here
}
// Export your other middleware…

然后,像这样使用它,请确保attachDb first ,以便在使用属性之前先分配该属性:

router.use(attachDb(db)); // Before all other middleware that depend on req.db
…
// No need to call because this is already the middleware function, 
// able to use req.db, which was assigned via attachDb
router.use(needDbParam); 

答案 1 :(得分:-1)

为什么不仅仅将module.exports声明为一个函数:

module.exports = (db) => { 
    let module = {}; 

    module.doesNotNeedDbParam = (req, res) => {
        // Do Stuff
    };

    module.needsDbParam = (req, res) => { 
        // db now in scope
    };

    return module;
};

这就是您的somefile.js将会变成的:

const router = express.Router();
const db = initializeDb();

const doesNotNeedDbParam = require('./middleware')().doesNotNeedDbParam;
router.use(require('./middleware')(db).needsDbParam);

您也可以像这样设置一次:

const middleware = require('./middleware')(db);
const doesNotNeedParam = middleware.doesNotNeedParam;
router.use(middleware.needsDbParam);

这与您之前所做的并没有什么不同,但是现在您可以访问needsDbParam中的db了。如果您的initializeDb函数是异步的,那么在建立数据库之后,您将需要使用Promise或其他一些异步库来包括在内。