【问题标题】:exit from chain of route specific middleware in express/ nodejs从 express/nodejs 中的路由特定中间件链退出
【发布时间】:2013-06-18 09:47:07
【问题描述】:

我有一个用于该路由的“路由特定中间件”链,如下所示:

    var express = require('express');
    var server = express();
    var mw1 = function(req, resp, next) {
        //do stuff
        if (success) {
            next();
        } else {
            req.connection.destroy(); //without calling next()
        }
    };
    var mw2 = function(req, resp, next) {
        //do stuff
        if (success) {
            next();
        } else {
            req.connection.destroy(); //without calling next()
        }
    };
    server.post('/some/path', [mw1, mw2], function(req, resp) {
        //write response
    });

[mw1, mw2] 是特定于路由 /some/path 的中间件。

这与这样的服务器范围的中间件不同:

    server.use(mw1);
    server.use(mw2);

它适用于所有定义的路由。

现在我的问题是我想退出链条。 IE。如果successmw1 中为假,我不希望调用mw2。如果successmw2 中为假,我不会不调用路由函数。目前,无论 next() 是否被调用,mw1mw2 似乎都被调用了 - 我不知道为什么。

我该怎么做?

【问题讨论】:

    标签: javascript node.js express connect middleware


    【解决方案1】:

    您可以拨打next( 'route' ),如the express api reference, application routing section所说:

    可以给出多个回调,所有回调都被平等对待,并且行为 就像中间件一样,除了这些回调可能 调用next('route') 绕过剩余的路由回调。

    示例

    var express = require('express')
      , app = express()
    ;
    
    // keep an eye on the function names
    app.post( '/some/path', middleware1, middleware2, function route1( req, res, next ) {
          // write response
    });
    app.all( '*', function route2( req, res, next ) {
        // do something like handle a 404 request
    });
    app.use(function errorHandler( err, req, res, next ) {
        // handle error
    });
    
    function middleware1( req, res, next ) {
        // ...
        if ( !success ) {
            // bypasses middleware2 and route1, route2 will be called
            return next( 'route' );
        }
        // calls middleware2
        next();
    }
    // intentionally similar to middleware1 to keep things clear
    function middleware2( req, res, next ) {
        if ( !success ) {
          // bypasses route1 and route2
          // errorHandler will be called with the error
          return next( Error( 'middleware 2 failed' ) );
        }
        // calls route1
        next();
    }
    

    【讨论】:

    • @ laconbass 是的,我也读过那部分,但不太确定该怎么做。如何使用它来解决这个问题 - 我应该创建一个名为 /error 的路由并调用 next('/error'); 吗?
    • @bguiz 加了一个例子,希望对你有帮助
    【解决方案2】:

    稍加修改就得出了答案:

    var express = require('express');
    var server = express();
    var mw1 = function(req, resp, next) {
      //do stuff
      if (success) {
        next();
      } else {
        resp.send(406, 'Invalid because of this');
        req.connection.destroy(); //without calling next()
      }
    };
    var mw2 = function(req, resp, next) {
      //do stuff
      if (success) {
        next();
      } else {
        resp.send(406, 'Invalid because of that');
        req.connection.destroy(); //without calling next()
      }
    };
    server.post('/some/path', [mw1, mw2], function(req, resp) {
      //write response
    });
    

    诀窍是发送响应:resp.send(406, 'Invalid because of this');

    就在破坏连接之前:req.connection.destroy();

    实际上并没有破坏连接,我发现在一般情况下也可以。

    (但在我的具体情况下是必需的,并且超出了这个问题的范围。)

    如果响应已经发送,则 express 不会自动为您调用 next(),因为它似乎不会这样做。

    【讨论】:

    • 您可以简单地使用response.end() 就可以了。不需要req.connection.destroy()
    • @laconbass 啊,这是真的。如果您有兴趣,我的具体用例是在数据流的大小超过我定义的合理阈值时终止请求。为了防止这种情况发生,我想在检测到时明确地破坏连接。此外,如果我正确理解 express 文档,当您调用 resp.send(... 时,express 会自动调用 resp.end()
    • 您应该更改问题的标题。这回答了如何终止请求,而不是如何退出特定于路由的中间件链。
    • @laconbass 目标是退出中间件链,这是通过终止响应来实现的......所以我认为这个问题很好!无论如何感谢您的输入!
    【解决方案3】:

    我的印象是,如果您既不调用next() 也不在路由处理函数中发送响应,express 就会挂起。 FWIW我还没有使用数组,我的看起来像server.post('/some/path', mw1, mw2, function(req, resp) {...

    无论如何。一种替代方法可能是重构您的代码,以便您只有一个处理函数。你有充分的理由让 mw1 和 mw2 成为中间件,而不是你的处理程序调用的常规异步函数吗?

    var express = require('express');
    var server = express();
    
    var mw1 = function(req, res, callback) {
      // do stuff with req/res if necessary but don't send a response
      if (success) {
        callback(null);
      } else {
        callback('Error');
      }
    };
    
    var mw2 = function(req, res, callback) {
      //do other stuff but don't send a response
      if (success) {
        callback(null);
      } else {
        callback('Error');
      }
    };
    
    function mwBoth(req, res){
      mw1(req, res, function(err){
        if(err){ return res.send(500) };
        mw2(req, res, function(err){
          if(err){ return res.send(500) };
          // neither had an error
          res.redirect('/some/other/path');
        });
      });
    };
    
    server.post('/some/path', mwBoth);
    

    【讨论】:

    • @plato 确实,数组语法等价于非数组语法:These callbacks may be passed within arrays as well, these arrays are simply flattened when passedsee here
    • @ plato 我不确定您为什么会收到反对票,我认为您的回答是完全有效的。但是,我个人想要一个“适当”的解决方案,如果你愿意的话,它不会偏离 express 框架太多,即坚持使用 connectnext 的原则,因为我相当肯定我所描述的模式并不少见。
    • @ plato,很抱歉让 cmets 继续来,但是是的,我同意你的第一个断言。令我惊讶的是,当一个中间件函数没有调用next() 时,后续的中间件函数仍然被调用。这似乎是 express 中的错误,或者我错误地解释了 express 的文档。
    猜你喜欢
    • 1970-01-01
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    • 1970-01-01
    • 2018-11-08
    • 2020-07-21
    • 1970-01-01
    相关资源
    最近更新 更多