Express:一旦做出响应,中间件是否应该停止调用?

时间:2016-02-26 01:17:42

标签: node.js express

我有这个问题,其中在返回路由器对象的路由器文件中 - 中间件在响应完成后被调用。

我认为在路线之后放置的中间件永远不会被执行 对于那条路线,我特别认为如果有回应就行 已经给了。

主要问题:

中间件应该在响应后停止被调用吗?

Ex:调用端点“/ login”并发送响应时     中间件A和B都被调用。

注意:我已将路由器包装在更高阶的功能中 (对于socket.io功能,但这不是重点)。

代码示例:

var express = require('express');
var router = express.Router();

var wrappedRouter = function(val) {

    router.get('/login', function(req, res) {
        console.log("Inside login route");
        res.sendFile(path.resolve('login.html'))
    }

    router.use(function(req, res, next) {
        console.log("Exectuing middleware A");
    });

    router.use(function(req, res, next) {
        console.log("Exectuing middleware B");
    });

    router.get('/another-route', function(req, res) {
        res.sendFile(path.resolve('login.html'))
    }

    return router;

}
//Prints:
// Inside login route
// Exectuing middleware A
// Exectuing middleware B

3 个答案:

答案 0 :(得分:5)

你的假设是绝对正确的,如果你不打电话给下一个,链中的下一个中间件永远不会被执行,你所面临的问题是因为你已经猜到,由于你的页面正在请求静态资源,比如favicon或图像或任何其他(单独的请求)。要获得具体证据,您可以在提供明确请求时记录网址,并查看使用req.url发出的请求和执行的内容,如下所示

var express = require('express');
var router = express.Router();
var path = require('path');
var wrappedRouter = function(val) {
    router.get('/login', function(req, res) { 
        console.log("Inside login route: " + req.url);
        res.sendFile(path.resolve('login.html'))
    });

    router.use(function(req, res, next) {
        console.log("Exectuing middleware A: "  + req.url);
    });

    router.use(function(req, res, next) {
        console.log("Exectuing middleware B: "  + req.url);
    });

    router.get('/another-route', function(req, res) {
        res.sendFile(path.resolve('login.html'))
    });

    return router;
}

module.exports = wrappedRouter({});

req.url中注意console.log("Inside login route: " + req.url);这将附加当前的req资源,我们将能够识别所调用的内容和原因。如下图所示

Diagnostics

所以现在我们知道发生了什么以及为什么,现在让我们看看我们如何解决它。

在表达我们注册表达app的东西的顺序非常重要。我建议单独注册您的中间件(第一个),然后注册您的路由,这将增加您超级棒代码的可管理性!

话虽如此,由于序列很重要,在你的情况下发生了什么,表达顺序尝试每个中间件,直到它用完为止。因此,当服务器请求'favicon'(或其他一些静态资源)时,它会开始按顺序执行匹配的中间件。 “中间件A”处理请求并生成输出(请记住,不提供favicon,实际上没有任何操作,请求将继续处理,直到您下一次呼叫或发送响应内容。

您的问题的解决方案是在注册任何内容之前在app.js的开头注册一个静态文件夹。这样,当请求静态资源时,它们会立即被提供,静态资源中间件不能接受的其他请求会被传递到您的中间件。

不建议您提供服务文件,因为随着应用程序的增长,您可能会觉得难以管理,相反,您应该使用视图引擎/静态中间件来获得您想要实现的目标,如下面的代码所示

您的应用结构应如下所示,它将解决您的问题。

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

//This will return wrapped routers
var routes = require('./routes/index');
var other = require('./routes/other');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());

//Just after registering all request parsing middleware, register static middleware
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/others', other);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

如果你是新手,想要开始并看看有什么用,我写了一篇关于它的小博客,第一部分已经完成,其余的都在排队;)

Get started with Express and build RESTful api 在这一部分中,我将展示如何搭建一个快速应用程序,代码来自它。你可能会发现它很有帮助。

希望它有所帮助!如果您还有其他需要,请告诉我们!

答案 1 :(得分:1)

Express正在按照您定义的顺序执行中间件,生命周期不会以res.send()结束。

您可以使用它们,例如即使请求已经满足,也要进行后处理。

var wrappedRouter = function(val) {
    router.use(function(req, res, next) {
        request.startProcessingTime = +(new Date());
        next();
    });

    router.get('/another-route', function(req, res) {
        res.sendFile(path.resolve('login.html'))
    }

    (...)
    router.use(function(req, res, next) {
        req.endProcessingTime = +(new Date());
        next();
    });

    router.use(function(req, res, next) {
        console.log('Processing time:', req.endProcessingTime - req.startProcessingTime)
    });

    return router;

}

答案 2 :(得分:1)

我应该说的另一件事,请确保在next()中调用router.use(),如下所示。

router.use(function(req, res, next) {
    console.log("Exectuing middleware A");
    next();
});

router.use(function(req, res, next) {
    console.log("Exectuing middleware B");
    next();
});

router.get('/login', function(req, res) {
    console.log("Inside login route");
    res.send('Hello World');
});

哪个输出

Exectuing middleware A
Exectuing middleware B
Inside login route

如果next()

中未调用router.use()
router.use(function(req, res, next) {
    console.log("Exectuing middleware A");
    //next();
});

router.use(function(req, res, next) {
    console.log("Exectuing middleware B");
    //next();
});

router.get('/login', function(req, res) {
    console.log("Inside login route");
    res.send('Hello World');
});

输出:

Exectuing middleware A

此请求的浏览器中的响应正在等待...