首页 > 解决方案 > 如何仅将参数传递给需要它的中间件?

问题描述

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

对于不需要db对象的函数来说这很简单,但是鉴于下面的代码结构,我如何引用该db对象,doesNotNeedDbParam因为它已经有 params reqresnext?

一些文件.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()

中间件.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
  }
}

标签: javascriptnode.jsexpressmiddleware

解决方案


功能方法

我认为一个好的结构是尝试对你的中间件进行柯里化。这是中间件实践的一种模式,例如body-parserExpress 本身在内部使用serve-static. 这样,您只需要求一次,然后通过db您需要的地方,而不是您不需要的地方:

// 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对象once。这消除了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首先在使用它之前分配属性

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); 

推荐阅读