【问题标题】:Proper way to remove middleware from the Express stack?从 Express 堆栈中删除中间件的正确方法?
【发布时间】:2013-09-07 07:05:56
【问题描述】:

有没有一种规范的方法可以从堆栈中删除使用app.use 添加的中间件?似乎是should be possible to just modify the app.stack array directly,但我想知道是否有我应该首先考虑的记录方法。

【问题讨论】:

  • @elmigranto 这是一个过于简单化的观点。您可能希望以更动态的方式使用 Express 路由的原因有很多,在某些情况下可能需要添加/删除中间件。
  • 中间件栈在app._router.stack中

标签: node.js express connect


【解决方案1】:

我们可以这样写。

// route outside middleware

route.get("/list", (req, res)=>{
    res.send("from listing route");  
});

//use middleware

router.use(Middlewares.AuthMiddleware.isValidToken);

//routes inside the middleware

route.post("/create", (req, res)=>{
    res.send("from create route");  
});

route.delete("/delete", (req, res)=>{
    res.send("from delete route");  
});

所以基本上,在将中间件注入路由之前编写路由。

【讨论】:

  • 这不能回答问题。
【解决方案2】:

据我所知,没有办法删除中间件。但是,您可以随时分配一个布尔标志来“停用”中间件。

let middlewareA_isActivate = true;
// Your middleware code
function(req, res, next) {
   if (!middlewareA_isActivate) next();
   // .........
}
// Deactivate middleware
middlewareA_isActivate = false;

编辑:
通读 ExpressJs (4.x) 代码后,我注意到您可以通过 app._router.stack 访问中间件堆栈,我猜是从那里开始的操作。不过,我认为这个“技巧”在未来的 Express 中可能无法使用
P/s:虽然没有测试 Express 在直接操作中间件堆栈时的行为方式

【讨论】:

    【解决方案3】:

    根据上面的提示,我在 express 4.x 上添加了以下内容。我的用例是记录 Slack Bolt 的内容,因此我可以捕获并模拟它:

    // Define a handy function for re-ordering arrays
    Array.prototype.move = function(from, to) {
      this.splice(to, 0, this.splice(from, 1)[0]);
    };
    
    // Use the normal use mechanism, so that 'extra' stuff can be done
    // For example, to log further up the order, use app.use(morgan("combined"))
    app.use([my-middleware]); 
    
    // Now adjust the position of what I just added forward
    const numElements = app._router.stack.length;
    app._router.stack.move(numElements - 1, 1);
    

    你可以使用 console.log("Stack after adjustment", app._router.stack) 确认新订单是您想要的。 (对于 Slack Bolt,我必须使用 app.receiver.app,因为 Bolt 应用程序包装了 express 应用程序。)

    【讨论】:

      【解决方案4】:

      如果您从基于 express 构建的框架继承一些不需要的中间件,这是一个有用的功能。

      基于我面前的一些答案:在 express 4.x 中,可以在 app._router.stack 中找到中间件。注意中间件是按顺序调用的。

      // app is your express service
      
      console.log(app._router.stack)
      // [Layer, Layer, Layer, ...]
      

      提示:您可以在各个图层中搜索要删除/移动的图层

      const middlewareIndex = app._router.stack.findIndex(layer => {
       // logic to id the specific middleware
      });
      

      然后您可以使用标准数组方法(例如 splice/unshift/etc)移动/移除它们

      // Remove the matched middleware
      app._router.stack.splice(middlewareIndex, 1);
      

      【讨论】:

      • 快速说明:下划线表示app._router 是私有的,即不是公共 API 的一部分,因此可以在不同版本之间更改。这可能只应作为最后的手段使用,但它肯定是可行的。不过感谢您的良好解释。
      【解决方案5】:

      你可以使用 express-dynamic-middleware 来做这个。

      https://github.com/lanbomo/express-dynamic-middleware

      这样使用

      const express = require('express');
      
      // import express-dynamic-middleware
      const dynamicMiddleware = require('express-dynamic-middleware');
      
      
      // create auth middleware
      const auth = function(req, res, next) {
          if (req.get('Authorization') === 'Basic') {
              next();
          } else {
              res.status(401).end('Unauthorization');
          }
      };
      
      // create dynamic middleware
      const dynamic = dynamicMiddleware.create(auth);
      
      // create express app
      const app = express();
      
      // use the dynamic middleware
      app.use(dynamic.handle());
      
      // unuse auth middleware
      dynamic.unuse(auth);
      

      【讨论】:

        【解决方案6】:

        似乎没有内置的方法可以做到这一点,但你可以通过一个小技巧来获得相同的结果。创建您自己的中间件数组(我们称之为dynamicMiddleware),但不要将其推送到 express 中,而是仅推送 1 个中间件,它将异步并按顺序执行 dynamicMiddleware 中的所有处理程序。

        const async = require('async')
        
        // Middleware 
        const m1 = (req, res, next) => {
            // do something here 
            next();
        }
        
        const m2 = (req, res, next) => {
            // do something here 
            next();
        }
        
        const m3 = (req, res, next) => {
            // do something here 
            next();
        }
        
        let dynamicMiddleware = [m1, m2, m3]
        
        app.use((req, res, next) => {
            // execute async handlers one by one
            async.eachSeries(
                // array to iterate over
                dynamicMiddleware, 
                // iteration function
                (handler, callback) => {
                    // call handler with req, res, and callback as next
                    handler(req, res, callback)
                }, 
                // final callback
                (err) => {
                    if( err ) {
                    // handle error as needed
        
                    } else {
                        // call next middleware
                        next()
                    }
                }
            );
        })
        

        代码有点粗糙,因为我现在没有机会测试它,但想法应该很清楚:将所有动态处理程序数组包装在 1 个中间件中,它将循环遍历数组。当您向数组添加或删除处理程序时,只会调用数组中剩下的处理程序。

        【讨论】:

        • 这不一定能解决问题。至少在我的用例中,对挂载点和方法进行不同的处理很重要。看来修改内部堆栈还是可以的,只是稍微移动了一下。
        • 您能否更详细地说明您的用例。也许您可以将其包装在一个小模块中并在不同的安装点重用?
        【解决方案7】:

        use 实际上来自 Connect(不是 Express),而 all it really does is push the middleware function onto the app's stack

        所以你应该很好地将函数从数组中拼接出来。

        但是,请记住,app.stack 周围没有文档,也没有删除中间件的功能。您冒着未来版本的 Connect 更改与您的代码不兼容的风险。

        【讨论】:

        • express 使更改与您的代码不兼容。 express 不再依赖于connect,所以我认为这不再有效。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-05
        • 1970-01-01
        • 2020-08-03
        • 2013-08-11
        • 2020-02-19
        相关资源
        最近更新 更多