Node.js 从Express堆栈中删除中间件的正确方法?

Node.js 从Express堆栈中删除中间件的正确方法?,node.js,express,connect,Node.js,Express,Connect,是否有一种规范的方法可以从堆栈中删除添加了app.use的中间件?似乎是这样,但我想知道是否有一个文档化的方法我应该首先考虑。使用实际上来自Connect(不是Express),并且 所以你应该把函数从数组中拼接出来 但是,请记住,app.stack没有相关文档,也没有删除中间件的功能。您将面临未来版本的Connect可能会做出与您的代码不兼容的更改的风险。似乎没有内置的方法可以做到这一点,但您可以通过一个小技巧获得相同的结果。创建您自己的中间件数组(我们称之为dynamicMiddleware

是否有一种规范的方法可以从堆栈中删除添加了
app.use的中间件?似乎是这样,但我想知道是否有一个文档化的方法我应该首先考虑。

使用实际上来自Connect(不是Express),并且

所以你应该把函数从数组中拼接出来


但是,请记住,
app.stack
没有相关文档,也没有删除中间件的功能。您将面临未来版本的Connect可能会做出与您的代码不兼容的更改的风险。

似乎没有内置的方法可以做到这一点,但您可以通过一个小技巧获得相同的结果。创建您自己的中间件数组(我们称之为
dynamicMiddleware
),但不要将其放入express中,而是只推一个中间件,它将异步并按顺序执行
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()
            }
        }
    );
})
// app is your express service

console.log(app._router.stack)
// [Layer, Layer, Layer, ...]

代码有点粗糙,因为我现在没有机会对其进行测试,但想法应该很清楚:将所有动态处理程序数组封装在一个中间件中,该中间件将在数组中循环。在向数组添加或删除处理程序时,只会调用数组中剩余的处理程序。

据我所知,无法删除中间件。但是,您可以随时为“停用”中间件指定布尔标志

let middlewareA_isActivate = true;
// Your middleware code
function(req, res, next) {
   if (!middlewareA_isActivate) next();
   // .........
}
// Deactivate middleware
middlewareA_isActivate = false;
编辑:
在阅读了ExpressJs(4.x)代码之后,我注意到您可以通过
应用程序访问中间件堆栈。_router.stack
,我猜操作就是从那里开始的。不过,我认为这一“伎俩”在future Express中可能无法奏效

P/s:未测试Express在直接操作中间件堆栈时的行为,尽管您可以使用Express动态中间件来实现这一点

像这样使用它

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);

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

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

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()
            }
        }
    );
})
// 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
});
然后,您可以使用标准阵列方法(如拼接/取消移位等)移动/移除它们

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

根据以上提示,我在Express4.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(“调整后堆叠”,app.\u router.Stack)

确认新订单是您想要的。(对于Slack Bolt,我必须使用
app.receiver.app
,因为Bolt应用程序包装了express应用程序。)

我们可以这样写

// 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");  
});

因此,基本上,在将中间件注入路由之前先编写路由。

express
进行与代码不兼容的更改
express
不再依赖于
connect
,因此我认为这不再有效。@elmigranto这是一个过于简单的观点。您可能希望以更动态的方式使用快速路由有很多原因,在某些情况下可能需要添加/删除中间件。中间件堆栈在应用程序中。\u router.stack这不一定能解决问题。至少在我的用例中,对装载点和方法进行不同的处理是很重要的。似乎修改内部堆栈仍然是可能的,只是被移动了一点。你能更详细地说明你的用例吗。也许您可以将其封装在一个小模块中,并在不同的安装点重复使用?简要说明:下划线表示
app.\u router
是专用的,即不属于公共API的一部分,因此可能会在不同版本之间更改。这可能只是作为最后的手段,但肯定是可行的。谢谢你的解释,但这并不能回答问题。