【问题标题】:Express Router Middleware Called Multiple Times多次调用 Express 路由器中间件
【发布时间】:2019-01-26 03:35:40
【问题描述】:

使用 Express 和 Express 路由器。我在一个目录中有几个文件都实现了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 中的路由,则会调用中间件 3 次。 等等 等等

【问题讨论】:

    标签: express express-router


    【解决方案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();
                }
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-12
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 2017-03-08
      • 1970-01-01
      相关资源
      最近更新 更多