Nodejs 为什么我的中间件是在路由执行完之后执行?

Nodejs 为什么我的中间件是在路由执行完之后执行?

console里显示,先执行的GET请求,再是加载js,图片什么的,最后在再执行中间件。 是不是我的中间件顺序错了?请大家看下:

/**
 * Module dependencies.
 */

var express = require('express');
var routes = require('./routes');
var http = require('http');
var path = require('path');
//配置文件
var config = require('./config').config;
//获取地址
// host: http://127.0.0.1
var urlinfo = require('url').parse(config.host);
config.hostname = urlinfo.hostname || config.host;




var app = express();
app.configure(function(){
    // all environments
    app.set('port', process.env.PORT || config.port);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'ejs');
    app.use(express.favicon());
    //console.log设置展示时间
    app.use(express.logger('dev'));
    //是Connect内建的middleware,设置此处可以将client提交过来的post请求放入request.body中。
    app.use(express.bodyParser());
    //methodOverride放在bodyParser下方用于包含表单值的req.body
    app.use(express.methodOverride());
    //添加cooket和session
    app.use(express.cookieParser());
    app.use(express.session({
        secret: config.session_secret
    }));
    //添加路由机制
    app.use(app.router);
    //设置静态文件位置
    app.use(express.static(path.join(__dirname, 'public')));

});

/*
// 错误处理机制在开发模式下将错误输出出来
if ('development' == app.get('env')) {
    app.use(express.errorHandler());
}*/

//设置生产环节和开发环境
var maxAge = 3600000 * 24 * 30;
var staticDir = path.join(__dirname, 'public');
app.configure('development', function () {
    app.use(express.static(staticDir));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function () {
    app.use(express.static(staticDir, { maxAge: maxAge }));
    app.use(express.errorHandler());
    app.set('view cache', true);
});


// set static, dynamic helpers 设置config
app.use(function (req, res, next) {
    console.log('config');
    res.locals.config = config;
    return next();
});

app.use(require('./controllers/sign').auth_user);


//设置防范csrf攻击
// custom middleware
var csrf = express.csrf();
app.use(function (req, res, next) {
    console.log('csrf');
    csrf(req, res, next);
});

//检测完csrf后设置_csrf为空。
app.use(function(req, res, next){
    res.locals.csrf = req.session ? req.session._csrf : '';
    //res.locals.req = req;
    //res.locals.session = req.session;
    console.log('csrf is ' + res.locals.csrf);
    next();
});

routes(app);

http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});

5 回复

Node.js 为什么我的中间件是在路由执行完之后执行?

在你的描述中,你提到在控制台中看到的是先执行 GET 请求,然后加载 JavaScript 和图片等静态资源,最后才执行中间件。这可能是因为中间件的顺序和执行时机导致的误解。

实际上,Express 中间件的执行顺序是非常灵活的,主要取决于它们在应用中的注册顺序。如果你希望某些中间件在特定路由之前或之后执行,你需要确保这些中间件被正确地注册在相应的路由之前或之后。

示例代码解析

让我们来看一下你的代码片段,并解释为什么中间件按当前顺序执行。

var express = require('express');
var routes = require('./routes');
var http = require('http');
var path = require('path');

var app = express();

// 配置中间件
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({
    secret: config.session_secret
}));
app.use(app.router);  // 这里注册了路由
app.use(express.static(path.join(__dirname, 'public')));

在这个例子中:

  1. app.use(express.favicon()); - 注册了一个 favicon 的中间件。
  2. app.use(express.logger('dev')); - 注册了一个日志记录中间件。
  3. app.use(express.bodyParser()); - 注册了一个解析 POST 请求体的中间件。
  4. app.use(express.methodOverride()); - 注册了一个方法覆盖中间件。
  5. app.use(express.cookieParser()); - 注册了一个解析 cookie 的中间件。
  6. app.use(express.session({ secret: config.session_secret })); - 注册了一个会话管理中间件。
  7. app.use(app.router); - 注册了路由中间件。这意味着在此之后定义的所有中间件都会在路由匹配之前执行。
  8. app.use(express.static(path.join(__dirname, 'public'))); - 注册了一个静态文件服务中间件。

中间件执行顺序

根据 Express 的工作流程,当一个请求到达时,中间件会按照注册的顺序依次执行,直到找到匹配的路由。如果路由没有匹配到任何中间件,则继续执行剩余的中间件。因此,app.use(app.router); 之前的中间件会在路由匹配之前执行,而之后的中间件则会在路由匹配之后执行。

示例代码调整

如果你想让某个中间件在特定路由之前执行,你可以将其放置在该路由之前:

app.use(function (req, res, next) {
    console.log('config');
    res.locals.config = config;
    return next();
});

app.use('/some-route', function (req, res, next) {
    console.log('This will be executed before the route /some-route');
    next();
});

app.get('/some-route', function (req, res) {
    // 处理请求
    res.send('Hello World!');
});

这样,/some-route 路由会首先调用第一个中间件,然后调用第二个中间件,最后处理实际的路由逻辑。

通过理解中间件的注册顺序,你可以更好地控制中间件的执行时机,从而满足你的需求。


POST /login 302 3ms - 58b
GET / 200 4ms - 5.23kb
GET /stylesheets/bootstrap.css 304 1ms
GET /stylesheets/bootstrap-responsive.css 304 1ms
GET /stylesheets/darkstrap.css 304 2ms
GET /javascripts/jquery.js 304 2ms
GET /javascripts/bootstrap.js 304 3ms
GET /Page 200 6ms - 6.54kb
GET /stylesheets/bootstrap.css 304 2ms
GET /stylesheets/bootstrap-responsive.css 304 7ms
GET /stylesheets/darkstrap.css 304 2ms
GET /javascripts/jquery.js 304 4ms
GET /javascripts/bootstrap.js 304 3ms
GET /imageAlbum/16 200 6ms - 5.52kb
GET /stylesheets/bootstrap.css 304 2ms
GET /stylesheets/bootstrap-responsive.css 304 2ms
GET /stylesheets/darkstrap.css 304 3ms
GET /javascripts/jquery.js 304 5ms
GET /javascripts/bootstrap.js 304 6ms
config
auto login
have session user

附上命令行,命令行最下面是执行中间件方法时返回的信息

你把router配置在其他中间件前面了

//添加路由机制
app.use(app.router);

写反了吧,理论上express基于connect,是按定义的顺序执行的。你把rount定义为一个中间件到最后当然就这样了。

从你提供的代码来看,你的中间件顺序看起来是正确的。不过,问题可能是由于中间件的执行顺序以及HTTP请求的不同阶段导致的。

在Express应用中,中间件会在路由之前和之后执行。你可以通过以下几点来理解为什么你的中间件会在路由执行之后才执行:

  1. 静态资源加载app.use(express.static(path.join(__dirname, 'public'))); 这行代码定义了Express如何处理静态资源(如JavaScript、CSS和图片)。这些资源通常会在HTML页面加载时被客户端浏览器请求。

  2. 路由处理routes(app); 这行代码定义了所有HTTP路由的处理逻辑。它会根据请求的URL路径匹配相应的处理函数,并在匹配到的情况下执行。

  3. 自定义中间件:在你的代码中,自定义中间件位于路由定义之后。它们会在路由处理完成后被调用。例如,app.use(function (req, res, next) { ... }); 定义了一个中间件,它会在路由处理完成之后才被执行。

示例代码

假设你有一个简单的路由定义如下:

app.get('/test', function(req, res) {
    console.log('Handling /test route');
    res.send('Hello World!');
});

那么请求 /test 的整个流程可能如下:

  1. 客户端发送一个请求到 /test
  2. Express找到匹配的路由 /test 并开始处理。
  3. 静态资源会被加载(如果存在)。
  4. 路由处理完成并返回响应。
  5. 自定义中间件被执行。

解释

如果你发现某些中间件似乎在路由之后执行,这可能是因为请求过程中有其他静态资源或子路由触发了这些中间件。你可以通过日志记录来调试和确认这一点。

希望这能帮助你理解Express中间件的工作原理。

回到顶部