多次调用 Express 路由器中间件
Express Router Middleware Called Multiple Times
使用 Express 和 Express Router。我在一个目录中有一些文件都实现了 Express.Router
。我动态地需要它们,添加一些中间件,然后将它们附加到 "meta" 路由器,最后调用 app.use("/",MetaRouter)
.
我的问题是中间件在每个路由中被多次调用。
这里是/index.js
:
const express = require('express')
const bodyParser = require('body-parser');
const app = express();
const port = 4000;
var cors = require('cors')
var routes = require('./routes');
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(routes);
app.listen(port, '0.0.0.0', () => console.log(`Example app listening on port ${port}!`))
需要/routes/index.js
:
const fs = require('fs');
const path = require('path');
var express = require('express');
var MetaRouter = express.Router();
var passport = require('passport');
const files = fs.readdirSync(__dirname).filter(file => file !== 'index.js');
const fileModules = {};
var middleware = function(req, res, next) {
console.log('In The Middleware');
next();
}
files.forEach(file => {
const { name } = path.parse(file);
fileModules[name] = require(`./${name}`);
});
Object.entries(fileModules).forEach(([key, _router]) => {
_router.use(middleware);
MetaRouter.use(_router);
});
module.exports = MetaRouter;
这里是目录中路由器文件之一的示例:
const BoxRequestService = require("../services/request/box_request_service.js");
var express = require('express');
var router = express.Router();
router.get('/box',
async function (req, res) {
res.json(await BoxRequestService.getAll(req, res));
});
router.get('/box/:id',
async function (req, res) {
res.json(await BoxRequestService.findById(req, res));
}
);
router.put('/box/:id',
async function (req, res) {
res.json(await BoxRequestService.update(req, res));
});
router.post('/box', async function (req, res) {
res.json(await BoxRequestService.create(req, res));
});
module.exports = router;
预期结果
所以当请求 http://localhost/box 时,我希望在控制台中只看到一次 "In The Middleware"。
实际结果
相反,我看到 "In The Middleware" 记录了多次。它还取决于所需文件的顺序。所以给出这个文件列表(按此顺序需要):
- /routes/A.js
- /routes/B.js
- /routes/C.js
- /routes/D.js
如果请求A.js
中的路由,则调用一次中间件。
如果请求 B.js
中的路由,则调用中间件两次。
如果请求C.js
中的路由,则中间件被调用三次。
等等
等等
Express 中间件不是按路由器实例附加,而是按路径附加。因为我没有指定路径,所以我对 _router.use(middleware);
的调用将我的中间件附加到所有路径。因为我在循环中调用它,所以我只是多次将相同的中间件添加到所有路径。
为了解决这个问题,并仍然获得动态要求我的个人路由器文件的好处,我对我的代码进行了一些更改。
首先,我在每个路由器文件中添加了一个 "metadata" 小对象。它有两个字段。一个包含路由 "prefix"(文件中每个路由的开头路径)和一些说明该文件中的路由是否需要授权的内容(我的中间件正在执行授权)。
然后我从该路由器文件中导出路由器和元数据。
现在回到我的 `/routes/index.js' 文件 ...
在那里,我仍然动态地需要所有单独的路由,并附加中间件。但是,我使用路由器的元数据来使用它的前缀附加路由器,因此我不会一遍又一遍地将中间件应用于相同的路由路径。
/routes/index.js
const fs = require('fs');
const path = require('path');
const auth_service = require('./../utils/auth_service');
var express = require('express');
var MetaRouter = express.Router();
// collect all of the legitimate router files
const files = fs.readdirSync(__dirname).filter(file => file !== 'index.js');
// pull in each "child" router, attach it to the "meta router" and apply middleware
files.forEach(file => {
const { name } = path.parse(file);
_router = require(`./${name}`);
MetaRouter.use(_router.router_metadata.endpoint_prefix, auth_service.auth_middleware(_router.router_metadata), _router.router);
});
module.exports = MetaRouter;
我的一个路由器文件
const BoxRequestService = require("../services/request/box_request_service.js");
var express = require('express');
var router = express.Router();
const router_metadata = {
endpoint_prefix: '/box',
requires_auth: true
}
router.get('/:id',
async function (req, res) {
res.json(await BoxRequestService.findById(req, res));
}
);
router.put('/:id',
async function (req, res) {
res.json(await BoxRequestService.update(req, res));
});
router.post('/', async function (req, res) {
res.json(await BoxRequestService.create(req, res));
});
router.get('/',
async function (req, res) {
res.json(await BoxRequestService.getAll(req, res));
});
module.exports = { router, router_metadata };
而且,这里是我定义中间件的地方
在这里,我使用路由器的元数据来确定中间件是否应该应用于它的路径。
var passport = require('passport');
require('../config/passport')(passport);
let self = module.exports = {
auth_middleware: function(router_metadata){
return function (req, res, next) {
if (router_metadata.requires_auth) {
passport.authenticate('jwt', { session: false }, function (err, user, info) {
if (err) { return next(err); }
if (!user) {
res.status("401");
return res.send("Unauthorized").end();
}
req.user = user;
next();
})(req, res, next);
} else {
next();
}
}
}
}
使用 Express 和 Express Router。我在一个目录中有一些文件都实现了 Express.Router
。我动态地需要它们,添加一些中间件,然后将它们附加到 "meta" 路由器,最后调用 app.use("/",MetaRouter)
.
我的问题是中间件在每个路由中被多次调用。
这里是/index.js
:
const express = require('express')
const bodyParser = require('body-parser');
const app = express();
const port = 4000;
var cors = require('cors')
var routes = require('./routes');
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(routes);
app.listen(port, '0.0.0.0', () => console.log(`Example app listening on port ${port}!`))
需要/routes/index.js
:
const fs = require('fs');
const path = require('path');
var express = require('express');
var MetaRouter = express.Router();
var passport = require('passport');
const files = fs.readdirSync(__dirname).filter(file => file !== 'index.js');
const fileModules = {};
var middleware = function(req, res, next) {
console.log('In The Middleware');
next();
}
files.forEach(file => {
const { name } = path.parse(file);
fileModules[name] = require(`./${name}`);
});
Object.entries(fileModules).forEach(([key, _router]) => {
_router.use(middleware);
MetaRouter.use(_router);
});
module.exports = MetaRouter;
这里是目录中路由器文件之一的示例:
const BoxRequestService = require("../services/request/box_request_service.js");
var express = require('express');
var router = express.Router();
router.get('/box',
async function (req, res) {
res.json(await BoxRequestService.getAll(req, res));
});
router.get('/box/:id',
async function (req, res) {
res.json(await BoxRequestService.findById(req, res));
}
);
router.put('/box/:id',
async function (req, res) {
res.json(await BoxRequestService.update(req, res));
});
router.post('/box', async function (req, res) {
res.json(await BoxRequestService.create(req, res));
});
module.exports = router;
预期结果
所以当请求 http://localhost/box 时,我希望在控制台中只看到一次 "In The Middleware"。
实际结果
相反,我看到 "In The Middleware" 记录了多次。它还取决于所需文件的顺序。所以给出这个文件列表(按此顺序需要):
- /routes/A.js
- /routes/B.js
- /routes/C.js
- /routes/D.js
如果请求A.js
中的路由,则调用一次中间件。
如果请求 B.js
中的路由,则调用中间件两次。
如果请求C.js
中的路由,则中间件被调用三次。
等等
等等
Express 中间件不是按路由器实例附加,而是按路径附加。因为我没有指定路径,所以我对 _router.use(middleware);
的调用将我的中间件附加到所有路径。因为我在循环中调用它,所以我只是多次将相同的中间件添加到所有路径。
为了解决这个问题,并仍然获得动态要求我的个人路由器文件的好处,我对我的代码进行了一些更改。
首先,我在每个路由器文件中添加了一个 "metadata" 小对象。它有两个字段。一个包含路由 "prefix"(文件中每个路由的开头路径)和一些说明该文件中的路由是否需要授权的内容(我的中间件正在执行授权)。
然后我从该路由器文件中导出路由器和元数据。
现在回到我的 `/routes/index.js' 文件 ...
在那里,我仍然动态地需要所有单独的路由,并附加中间件。但是,我使用路由器的元数据来使用它的前缀附加路由器,因此我不会一遍又一遍地将中间件应用于相同的路由路径。
/routes/index.js
const fs = require('fs');
const path = require('path');
const auth_service = require('./../utils/auth_service');
var express = require('express');
var MetaRouter = express.Router();
// collect all of the legitimate router files
const files = fs.readdirSync(__dirname).filter(file => file !== 'index.js');
// pull in each "child" router, attach it to the "meta router" and apply middleware
files.forEach(file => {
const { name } = path.parse(file);
_router = require(`./${name}`);
MetaRouter.use(_router.router_metadata.endpoint_prefix, auth_service.auth_middleware(_router.router_metadata), _router.router);
});
module.exports = MetaRouter;
我的一个路由器文件
const BoxRequestService = require("../services/request/box_request_service.js");
var express = require('express');
var router = express.Router();
const router_metadata = {
endpoint_prefix: '/box',
requires_auth: true
}
router.get('/:id',
async function (req, res) {
res.json(await BoxRequestService.findById(req, res));
}
);
router.put('/:id',
async function (req, res) {
res.json(await BoxRequestService.update(req, res));
});
router.post('/', async function (req, res) {
res.json(await BoxRequestService.create(req, res));
});
router.get('/',
async function (req, res) {
res.json(await BoxRequestService.getAll(req, res));
});
module.exports = { router, router_metadata };
而且,这里是我定义中间件的地方
在这里,我使用路由器的元数据来确定中间件是否应该应用于它的路径。
var passport = require('passport');
require('../config/passport')(passport);
let self = module.exports = {
auth_middleware: function(router_metadata){
return function (req, res, next) {
if (router_metadata.requires_auth) {
passport.authenticate('jwt', { session: false }, function (err, user, info) {
if (err) { return next(err); }
if (!user) {
res.status("401");
return res.send("Unauthorized").end();
}
req.user = user;
next();
})(req, res, next);
} else {
next();
}
}
}
}