【问题标题】:How to automate next() call in every route function? (express.js)如何在每个路由函数中自动化 next() 调用? (express.js)
【发布时间】:2020-06-01 22:24:40
【问题描述】:

您好,我面临的问题是我需要在数据库中记录每个传入请求和相关响应。我当前的解决方案如下所示:

./routes/customer.js

router.get('/', async (req, res, next) => {
    req.allCustomers = await fetchAllCustomers();
    res.status(200).send(req.allCustomers);
    next();  // <- this is my personal problem
});

./middleware/logging.js

module.exports = function (req, res, next) {
    db.query(
        `INSERT INTO logging SET ?`, 
         { 
            request: JSON.stringify([req.body, req.params]), 
            response: JSON.stringify(req.response) 
         }
    );
}

路由声明

module.exports = function(app) {
    app.use(express.json());
    app.use('/api/customers', customers); // <- ROUTE ./routes/customer.js
    app.use(logging); // <- MIDDLEWARE ./middleware/logging.js
}

我已经在我的第一段代码中提到了我的问题。在每条路线中手动调用next() 确实是重复的,我想避免这种情况。我已经尝试在所有路由之前加载中间件,在中间件函数中调用next(),然后执行我的数据库查询,但由于异步功能,我此时没有响应。

有什么办法可以处理这种情况,还是我需要在每个路由函数结束时继续调用next()

【问题讨论】:

    标签: javascript node.js express routes


    【解决方案1】:

    如果您不想从路由中调用next(),则不能让中间件在它们之后运行。它需要放在前面。但是你能在路由之前运行的中间件中得到响应吗?答案是肯定的!

    这可能有点笨拙,但由于您的路线使用res.send(),您可以利用它来发挥自己的优势。通过在你的路由之前运行,你的中间件可以劫持 res.send 函数,让它做其他事情。

    ./routes/customer.js

    router.get('/', async (req, res, next) => {
        req.allCustomers = await fetchAllCustomers();
        res.send(req.allCustomers); // We'll hijack this
    });
    

    ./middleware/logging.js

    module.exports = function (shouldBeLoggedFunc) {
      return function (req, res, next) {
        if (shouldBeLoggedFunc(req)) {
          // Store the original send method
          const _send = res.send;
          // Override it
          res.send = function (body) {
            // Reset it
            res.send = _send;
            // Actually send the response
            res.send(body);
            // Log it (console.log for the demo)
            console.log(`INSERT INTO logging SET ?`, {
              request: JSON.stringify([req.body, req.params]),
              response: JSON.stringify(body)
            });
          };
        }
        next();
      };
    };
    

    路线声明

    function shouldBeLogged(req) {
      // Here, check the route and method and decide whether you want to log it
      console.log(req.method, req.path); // e.g. GET /api/customers
      return true;
    }
    
    module.exports = function(app) {
        app.use(express.json());
        app.use(logging(shouldBeLogged)); // <- Place this before your routes
        app.use('/api/customers', customers);
    };
    

    【讨论】:

    • 像魅力一样工作。十分感谢!想知道为什么这不是节点的“默认”可能性。
    【解决方案2】:

    当您像以前一样使用 express.Router 类时,然后使用此代码

    app.use('/api/customers', customers);

    您不必在 router.get 的回调函数中编写“next()”。

    有一个例子 在app目录下创建一个名为birds.js的路由文件,内容如下:

    var express = require('express')
    var router = express.Router()
    
    // middleware that is specific to this router
    router.use(function timeLog (req, res, next) {
      console.log('Time: ', Date.now())
      next()
    })
    // define the home page route
    router.get('/', function (req, res) {
      res.send('Birds home page')
    })
    // define the about route
    router.get('/about', function (req, res) {
      res.send('About birds')
    })
    
    module.exports = router

    然后,在应用中加载路由器模块:

    var birds = require('./birds')
    
    // ...
    
    app.use('/birds', birds)

    【讨论】:

    • 我正面临这个解决方案的一个重要问题。无法使用req.params,也不包括响应。
    猜你喜欢
    • 1970-01-01
    • 2013-09-27
    • 2020-10-05
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-28
    相关资源
    最近更新 更多