如何仅将参数传递给需要它的中间件?
How to pass parameter only to middleware that need it?
我有一个 Express 应用程序,我正试图将我所有的中间件放在它自己的文件中。有些中间件函数需要 db
对象,有些则不需要。
对于不需要 db
对象的函数来说非常简单,但是鉴于我下面的代码结构,我如何在 doesNotNeedDbParam
中引用 db
对象,因为它已经有参数 req
、res
和 next
?
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
}
}
为什么不将 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
中的数据库。如果您的 initializeDb
函数是异步的,那么您将需要使用 Promise
或其他一些异步库来包含数据库设置后。
函数方法
我认为一个好的结构是尝试currying your middleware. This is a pattern practiced by middleware such as body-parser
and internally by Express itself with 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
是 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);
我有一个 Express 应用程序,我正试图将我所有的中间件放在它自己的文件中。有些中间件函数需要 db
对象,有些则不需要。
对于不需要 db
对象的函数来说非常简单,但是鉴于我下面的代码结构,我如何在 doesNotNeedDbParam
中引用 db
对象,因为它已经有参数 req
、res
和 next
?
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
}
}
为什么不将 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
中的数据库。如果您的 initializeDb
函数是异步的,那么您将需要使用 Promise
或其他一些异步库来包含数据库设置后。
函数方法
我认为一个好的结构是尝试currying your middleware. This is a pattern practiced by middleware such as body-parser
and internally by Express itself with 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
是 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);