Промежуточное программное обеспечение Express Router вызывается несколько раз
Использование Express и Express Router. У меня есть несколько файлов в одном каталоге, которые все реализуют Express.Router
, Я динамически требую их, добавив промежуточное программное обеспечение, а затем подключив их к "мета" маршрутизатору и, наконец, позвонив 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" в консоли ровно один раз.
Фактические результаты
Вместо этого я вижу "В промежуточном программном обеспечении", зарегистрировано несколько раз. Это также зависит от порядка, в котором файлы требуются. Итак, учитывая этот список файлов (требуется в этом порядке):
- /routes/A.js
- /routes/B.js
- /routes/C.js
- /routes/D.js
Если маршрут в A.js
запрашивается, промежуточное программное обеспечение вызывается один раз. Если маршрут в B.js
запрашивается, промежуточное программное обеспечение вызывается дважды. Если маршрут в C.js
запрашивается, промежуточное программное обеспечение вызывается три раза. и т. д.
1 ответ
Промежуточное программное обеспечение Express подключено не для каждого экземпляра маршрутизатора, а для каждого пути. Так как я не указывал путь, мой вызов _router.use(middleware);
было прикреплено мое промежуточное ПО ко всем путям. И поскольку я вызывал это в цикле, я просто добавлял одно и то же промежуточное программное обеспечение несколько раз ко всем путям.
Чтобы это исправить и все еще получить преимущества динамического запроса отдельных файлов маршрутизатора, я внес некоторые изменения в свой код.
Прежде всего, я добавил небольшой объект "метаданных" в каждый из файлов роутера. У него есть два поля. Один содержит "префикс маршрута" (путь, с которого будет начинаться каждый из маршрутов в файле) и что-то, что говорит, нужно ли авторизовать маршруты в этом файле (мое промежуточное ПО выполняет авторизацию).
Затем я экспортирую и маршрутизатор, и метаданные из этого файла маршрутизатора.
Теперь вернемся к моему файлу `/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();
}
}
}
}