express中如何理解app.use()
发布于 8 年前 作者 HuKaihe 10018 次浏览 来自 问答

我是nodejs新手,最近在学习express时,app.use()让我有点糊涂。 看官网上说app.use(function () {XXX})如果没有挂载路径,那么所有请求都会执行里面的回调函数。 但是在加载第三方模块时比如 app.use(flash()),岂不是每次请求都要执行以下里面的flash()吗? 我在网上查找,说有点像java ee的过滤器,但是如果某些请求所需要实现的功能和某个中间件的根本就没有任何关系,不会也还要执行那个中间件吧?那怎么理解和判断呢?望大神指点

7 回复

如果把一个http处理过程比作是污水处理,中间件就像是一层层的过滤网。每个中间件在http处理过程中通过改写request或(和)response的数据、状态,实现了特定的功能。

实际上你这里所描述的 app.use(flash()) 使用的是一个可配置的中间件。 flash() 执行的结果将返回一个函数,也就是平时常见到的这种形式:

function (req, res, next) {
  // do something
}

这样就跟直接使用这种形式差不多了

app.use(function (req, res, next) {
  // do something
})

你可以直接看 connect-flash 的源码实现:

module.exports = function flash(options) {
  options = options || {};
  var safe = (options.unsafe === undefined) ? true : !options.unsafe;
  
  return function(req, res, next) {
    if (req.flash && safe) { return next(); }
    req.flash = _flash;
    next();
  }
}

这样做的好处就是创建可以配置的中间件,根据调用 app.use(flash(options)) 传进来的 options 进行相应的处理。 还有不理解的,可以查看 Connect/Express 的中间件机制

你说的对,就是类似Java的管理器。

来自酷炫的 CNodeMD

@manxisuo 写错了,应该是过滤器。

来自酷炫的 CNodeMD

@modood 大神,还有这种情况我也是在看不懂 var routes = require(’./routes/index’); app.use(’/’, routes);

而index.js里的内容是返回的是一个对象module.exports = router;在router上挂着了很多路由,这该如何理解呢?

@HuKaihe 就是所有的请求都会经过这个路由处理。

@HuKaihe 提问最好贴一下源码,既然看不到你的源码,那我尝试猜一下…

app.js

var express = require('express');

var routes = require('./routes/index');

var app = express();

app.use('/', routes);

app.listen(3000);

./routes/index.js

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

router.get('/',  function (req, res, next) {
  return res.end('got root!');
})

router.get('/users',  function (req, res, next) {
  return res.end('got users!');
})

router.get('/users/:user_id/books',  function (req, res, next) {
  return res.end('got user ' + req.params.user_id + '\'s books!');
})

module.exports = router;

在 app.js 里使用了 app.use('/', routes),实际上这里等 routes 是 ./routes/index.js 文件中使用 express.Router() 生成的,这里翻一下 express.Router 的源码你会发现:

/**
 * Initialize a new `Router` with the given `options`.
 *
 * @param {Object} options
 * @return {Router} which is an callable function
 * @public
 */

var proto = module.exports = function(options) {
  var opts = options || {};

  function router(req, res, next) {
    router.handle(req, res, next);
  }

  // mixin Router class functions
  router.__proto__ = proto;

  router.params = {};
  router._params = [];
  router.caseSensitive = opts.caseSensitive;
  router.mergeParams = opts.mergeParams;
  router.strict = opts.strict;
  router.stack = [];

  return router;
};

看到了没,实际上 router 也是一个可配置的中间件。

回到开头,对于这个程序的理解:

  1. 如楼上所说的,app.use('/', routes); 就是所有的请求都会经过 routes 这个路由处理。

  2. routes 文件内部,挂载了很多路由(为什么在 router 上可以挂载路由?这个中间件和一般的中间件相比更复杂一点,具体的功能 express 内部已经实现好了,需要详细了解可以查看源码),各个路由对不同的请求跟进 URL 进行匹配再进行相应的处理,

比如:

请求: http://127.0.0.1:3000/
响应: got root!

请求: http://127.0.0.1:3000/users
响应: got users!

请求: http://127.0.0.1:3000/users/tom/books
响应: got user tom's books!
回到顶部