express.js 中 app.use 和 app.get 的区别

Posted

技术标签:

【中文标题】express.js 中 app.use 和 app.get 的区别【英文标题】:Difference between app.use and app.get in express.js 【发布时间】:2013-03-14 03:51:33 【问题描述】:

我对 express 和 node.js 有点陌生,我无法弄清楚 app.use 和 app.get 之间的区别。看来您可以同时使用它们来发送信息。例如:

app.use('/',function(req, res,next) 
    res.send('Hello');
    next();
);

好像和这个一样:

app.get('/', function (req,res) 
   res.send('Hello');
);

【问题讨论】:

看起来你得到了三个不同的答案,都对这个话题有所贡献:) 这是一个相关的问题***.com/questions/11321635/… 是的,所有答案都很好。谢谢,我去看看。 【参考方案1】:

app.get 在HTTP method 设置为GET 时被调用,而app.use 被调用而与HTTP 方法无关,因此定义了一个位于所有其他RESTful 类型之上的层包使您可以访问。

【讨论】:

【参考方案2】:

app.use() 用于将middleware 绑定到您的应用程序。 path 是“mount”或“prefix”路径,并将中间件限制为仅适用于开始 与它。它甚至可以用来嵌入另一个应用程序:

// subapp.js
var express = require('express');
var app = modules.exports = express();
// ...
// server.js
var express = require('express');
var app = express();

app.use('/subapp', require('./subapp'));

// ...

通过将/ 指定为“mount”路径,app.use() 将响应以/ 开头的任何路径,它们都是所有路径,并且与使用的 HTTP 动词无关:

GET / PUT /foo POST /foo/bar

另一方面,app.get() 是 Express 的 application routing 的一部分,用于在使用 GET HTTP 动词请求时匹配和处理特定路由:

GET /

而且,您的 app.use() 示例的等效路由实际上是:

app.all(/^\/.*/, function (req, res) 
    res.send('Hello');
);

更新:试图更好地展示差异。

包括app.get() 在内的路由方法是方便的方法,可帮助您更精确地调整对请求的响应。他们还添加了对 parameters 和 next('route') 等功能的支持。

在每个app.get() 中都调用了app.use(),因此您当然可以直接使用app.use() 完成所有这些操作。但是,这样做通常需要(可能不必要地)重新实现不同数量的样板代码。

例子:

对于简单的静态路由:

app.get('/', function (req, res) 
  // ...
);

对比

app.use('/', function (req, res, next) 
  if (req.method !== 'GET' || req.url !== '/')
    return next();

  // ...
);

同一路由有多个处理程序:

app.get('/', authorize('ADMIN'), function (req, res) 
  // ...
);

对比

const authorizeAdmin = authorize('ADMIN');

app.use('/', function (req, res, next) 
  if (req.method !== 'GET' || req.url !== '/')
    return next();

  authorizeAdmin(req, res, function (err) 
    if (err) return next(err);

    // ...
  );
);

带参数:

app.get('/item/:id', function (req, res) 
  let id = req.params.id;
  // ...
);

对比

const pathToRegExp = require('path-to-regexp');

function prepareParams(matches, pathKeys, previousParams) 
  var params = previousParams || ;

  // TODO: support repeating keys...
  matches.slice(1).forEach(function (segment, index) 
    let  name  = pathKeys[index];
    params[name] = segment;
  );

  return params;


const itemIdKeys = [];
const itemIdPattern = pathToRegExp('/item/:id', itemIdKeys);

app.use('/', function (req, res, next) 
  if (req.method !== 'GET') return next();

  var urlMatch = itemIdPattern.exec(req.url);
  if (!urlMatch) return next();

  if (itemIdKeys && itemIdKeys.length)
    req.params = prepareParams(urlMatch, itemIdKeys, req.params);

  let id = req.params.id;
  // ...
);

注意:Express 对这些功能的实现包含在其Router, Layer, and Route 中。

【讨论】:

感谢提及嵌入式应用程序。这是组织快速中间件的一种非常方便的方式。 是否可以说 app.use 可以完成 app.get、app.post、app.put 中的每一个操作,但反之则不行? 还是很难理解。 很高兴知道 用于 的 use 和 get 是什么,但没有人能很好地解释它们的功能有何不同。据我所知,所有 .use 处理程序首先运行,并且 .use 匹配任何 begins 与指定路径的路径(即 .use('/', ...) 和 .get(' /*', ...) 将匹配相同的路径)。对我来说,当我能看到移动部件时,更容易理解整体概念。 我认为值得一提的是,这个响应已经过时了,截至我发表评论之日,您不再需要 path-to-regexp 或任何东西,您可以直接在第一个参数中使用路由参数use 方法。【参考方案3】:

app.use 是 Express 所依赖的中间件框架 Connect 中的“低级”方法。

这是我的指导方针:

如果要公开 GET 方法,请使用 app.get。 如果您想添加一些中间件(HTTP 请求到达您在 Express 中设置的路由之前的处理程序),或者如果您想使您的路由模块化(例如,从一个 npm 模块公开一组路由,其他 Web 应用程序可以使用)。

【讨论】:

但是如果我不关心方法,我可以使用app.use来处理一些路由吗?或者我们永远不应该使用app.use 进行路由。 您可以使用 app.use 将您的路线移动到单独的文件 eq。 users.js、buildings.js 尽管上面的一个答案已经收集了更多的 UP/AGREE,但您的答案将包括中间件在内的复杂事物转化为几个简单的词,kudo。【参考方案4】:

简单地说 app.use 的意思是“在所有请求上运行” app.get 的意思是“针对给定的 URL,在 GET 请求上运行它”

【讨论】:

没那么简单。阅读其他答案。【参考方案5】:

app.useapp.get 之间的区别:

app.use → 一般用于在你的应用中引入中间件,可以处理所有类型的HTTP请求。

app.get → 仅用于处理 GET HTTP 请求。

现在,app.useapp.all 之间存在混淆。毫无疑问,它们有一个共同点,即两者都可以处理所有类型的 HTTP 请求。 但是有一些差异建议我们将 app.use 用于中间件,将 app.all 用于路由处理。

    app.use() → 只需要一次回调。app.all() → 可以接受多次回调。

    app.use() 只会查看 url 是否以指定路径开头。 但是,app.all() 将匹配完整路径。

例如,

app.use( "/book" , middleware);
// will match /book
// will match /book/author
// will match /book/subject

app.all( "/book" , handler);
// will match /book
// won't match /book/author   
// won't match /book/subject    

app.all( "/book/*" , handler);
// won't match /book        
// will match /book/author
// will match /book/subject
    next()app.use() 内调用将调用下一个中间件或任何路由处理程序,但next()app.all() 内调用将只调用下一个路由处理程序(app.all()app.get/post/put... 等)。如果后面有任何中间件,将被跳过。因此,建议将所有中间件始终放在路由处理程序之上。

【讨论】:

您的第 3 点似乎不适用于 Express 4.16。在app.all('/*', ...) 内部调用next() 实际上会在文件后面执行app.use('/', ...)。也许我在那里误解了你。否则非常有用的解释。 在 4.17 中我观察到与@BeetleJuice 相同【参考方案6】:

除了以上的解释,我的体会:

app.use('/book', handler);  

将匹配所有 '/book' 作为 URL 的请求。所以它也匹配 '/book/1' 或 '/book/2'

app.get('/book')  

仅匹配具有完全匹配的 GET 请求。它不会处理像“/book/1”或“/book/2”这样的网址

因此,如果您想要一个处理所有路由的全局处理程序,那么app.use('/') 是选项。 app.get('/') 将只处理根 URL。

【讨论】:

【参考方案7】:

到目前为止,我发现了 3 个主要差异。第三个不是那么明显,你可能会觉得它很有趣。快递router 的区别是相同的。这意味着router.use()router.get()或其他postputall等方法也有相同的区别。 1

app.use(path, callback) 将响应任何 HTTP 请求。 app.get(path, callback) 只会响应 GET HTTP 请求。同理,postput 等也会响应其对应的请求。 app.all() 响应任何 HTTP 请求,因此 app.use()app.all() 在这部分是相同的。

2

app.use(path, callback) 将匹配请求路径的前缀,如果请求路径的任何前缀匹配路径参数,则响应。如路径参数为"/",则匹配"/""/about""/users/123"等。 app.get(path, callback) 这里的 get 将匹配整个路径。其他 HTTP 请求和app.all() 相同。如路径参数为"/",则只匹配"/"

3

next('route') 作用于app.use() 的中间件/回调函数。它仅适用于app.get()app.all()和其他HTTP请求的其他类似功能。

根据express文档

next('route') 仅适用于使用 app.METHOD() 或 router.METHOD() 函数加载的中间件函数。

METHOD 是中间件函数请求的 HTTP 方法 小写的句柄(例如 GET、PUT 或 POST)。

从这里我们将使用关键字 METHOD 代替 getpostall 等。 但是next('route')是什么?!

让我们看看。

下一个('路线')

我们看到,app.use()app.METHOD() 可以采用多个回调/中间件函数。

来自 express 文档

中间件函数是可以访问请求对象 (req)、响应对象 (res) 和应用程序请求-响应周期中的下一个中间件函数的函数。 next 中间件函数通常由名为 next 的变量表示。

如果当前中间件函数没有结束请求-响应循环,它必须调用 next() 将控制权传递给下一个中间件函数。否则,请求将被挂起。

所以我们看到每个中间件函数要么调用下一个中间件函数要么结束响应。 app.use()app.METHOD() 也是如此。

但有时在某些情况下,您可能希望跳过当前路由的所有下一个回调函数,但也不想立即结束响应。因为也许还有其他路线应该匹配。所以要跳过当前路由的所有回调函数而不结束响应,可以运行next('route')。它将跳过当前路由的所有回调函数并搜索匹配下一个路由。

例如(来自快速文档):

app.get('/user/:id', function (req, res, next) 
  // if the user ID is 0, skip to the next route
  if (req.params.id === '0') next('route')
  // otherwise pass the control to the next middleware function in this stack
  else next()
, function (req, res, next) 
  // send a regular response
  res.send('regular')
)

// handler for the /user/:id path, which sends a special response
app.get('/user/:id', function (req, res, next) 
  res.send('special')
)

看,这里在特定条件(req.params.id === '0') 我们想跳过下一个回调函数但又不想结束响应,因为有另一个相同路径参数的路由将被匹配并且该路由将发送一个特殊的回应。 (是的,对同一个METHOD多次使用相同的路径参数是有效的。在这种情况下,所有的路由都会匹配到响应结束)。所以在这种情况下,我们运行next('route') 并跳过当前路由的所有回调函数。这里如果条件不满足则调用下一个回调函数。

这种next('route') 行为只能在app.METHOD() 函数中实现。

快速文档中回顾:

next('route') 仅适用于使用 app.METHOD() 或 router.METHOD() 函数加载的中间件函数。

由于在app.use()不可能跳过当前路由的所有回调函数,所以我们在这里应该小心。我们应该只使用app.use() 中的中间件函数,在任何情况下都不需要跳过。因为要么要结束响应,要么要从头到尾遍历所有回调函数,根本不能跳过。

您可以访问here了解更多信息

【讨论】:

以上是关于express.js 中 app.use 和 app.get 的区别的主要内容,如果未能解决你的问题,请参考以下文章

从express js访问HTML元素

express.js app.post 中间件未触发

将 Express.js 与 React.js 一起使用的推荐方式?

express.js request.url 总是 /

如何在 express.js 中限制上传文件的大小

公共/私人休息 API