【问题标题】:Differences between express.Router and app.get?express.Router 和 app.get 的区别?
【发布时间】:2015-04-03 00:22:00
【问题描述】:

我从 NodeJS 和 Express 4 开始,我有点困惑。我一直在阅读 Express 网站,但看不到 何时 使用路由处理程序或何时使用 express.Router

如我所见,如果我想在用户点击/show 时显示页面或其他内容,例如我应该使用:

var express = require('express')    
var app = express()    
app.get("/show", someFunction)  

一开始,我认为这是旧的(对于 Express 3)。是这样吗,还是 Express 4 也是这样?

如果这是 Express 4 中的方法,express.Router 是用来做什么的?

我阅读了与上面几乎相同的示例,但使用的是express.Router

var express = require('express');
var router = express.Router();
router.get("/show", someFunction)

那么,这两个例子有什么区别呢?

如果我只想做一个简单的测试网站,我应该使用哪一个?

【问题讨论】:

  • A Router 不会 .listen() 单独处理请求。这对于将您的应用程序分成多个模块很有用——在每个模块中创建一个Routerapp 可以将require().use() 作为中间件。
  • 正如@JonathanLonowski 所暗示的,app.get(..) 语法只是让express.router 更方便使用的捷径。如果您刚刚开始,请不要担心路由器的细节。
  • 所以你是说我现在应该只使用 app.get()?仍然对何时使用一种或另一种感到困惑
  • @nelson687 它们之间并没有真正的硬性规则。如果您觉得app's 自己的路由方法,例如app.get(),足以满足您的需求,请使用它们。 Router 只是为了方便帮助您跨多个模块组织应用程序。 From the guide: "express.Router 类可用于创建模块化可挂载路由处理程序。Router 实例是一个完整的中间件和路由系统;因此它通常被称为“迷你应用程序” "."

标签: node.js express


【解决方案1】:

app.js

var express = require('express'),
    dogs    = require('./routes/dogs'),
    cats    = require('./routes/cats'),
    birds   = require('./routes/birds');

var app = express();

app.use('/dogs',  dogs);
app.use('/cats',  cats);
app.use('/birds', birds);

app.listen(3000);

dogs.js

var express = require('express');

var router = express.Router();

router.get('/', function(req, res) {
    res.send('GET handler for /dogs route.');
});

router.post('/', function(req, res) {
    res.send('POST handler for /dogs route.');
});

module.exports = router;

当调用var app = express() 时,会返回一个app 对象。将其视为主应用

当调用var router = express.Router() 时,会返回一个略有不同的小应用程序mini app 背后的理念是,您的应用程序中的每条路线都可能变得相当复杂,您可以从将所有这些代码移到一个单独的文件中受益。每个文件的路由器都变成了一个迷你应用,其结构与主应用非常相似。

在上面的示例中,/dogs 路由的代码已移至其自己的文件中,因此它不会弄乱主应用/cats/birds 的代码在它们自己的文件中的结构类似。通过将此代码分成三个小应用程序,您可以单独处理每个应用程序的逻辑,而不必担心它会如何影响其他两个应用程序。

如果您有与所有三个路由相关的代码(中间件),您可以将其放在 主应用程序 中,在 app.use(...) 调用之前。如果您的代码(中间件)仅与其中一个路由相关,则可以将其放入该路由的文件中。

【讨论】:

  • 你不应该在app.use('/dogs', dogs)(app) 上传递应用程序对象,因为你在那里定义路由,另外(如果我错了,请纠正我)如果你这样做的话应用程序对象之前放置了所有中间件,并且额外的中间件将被添加到应用程序对象中(假设更多的中间件在 dog 路线中)。如果您使用route.get('/dogs', route),它只会在与该路由器中定义的路由交互时将中间件传递给应用程序对象,并且如果应用程序的范围在路由之外,则它无权访问该中间件。跨度>
  • 您不需要将应用程序传递给路由,因为路由正在通过app.use('/dogs', show) 传递给应用程序。这样路由就独立于应用程序,并且可以在任何 Express 应用程序中重复使用。中间件放置在路由被该路由使用之前的任何位置。如果您将中间件放在 app.js 中的所有路由之上,那么所有路由都将使用该中间件。如果您将中间件放在路由文件 (dogs.js) 中,则只有该路由会使用它。如果你在 dog.js 中的 GET 路由之后放置中间件,那么只有 POST 路由会使用它(只要它以响应结尾)。
  • 当我使用 express.Router() 或 express() 时,我的应用程序仍然有效,我无法理解其中的区别 :(
  • @Ajay Suwalka 我不知道该如何详细说明我已经说过的话。文档说“路由器对象是中间件和路由的隔离实例”。我也喜欢上面的@Jonathan Lonowski 评论,“Router 不会 .listen() 自己提出请求”。这可能是主要区别。
  • @Shashwat 我不认为他们是一样的。 Router() 在 require('express') 模块中定义和导入。看起来 require('router') 正在导入一个完全不同的模块,根本与 Express 无关。
【解决方案2】:

Express 4.0 带有新的路由器。如网站所述:

express.Router 类可用于创建模块化可挂载路由 处理程序。 Router 实例是一个完整的中间件和路由 系统;因此,它通常被称为“迷你应用”。

https://scotch.io/tutorials/learn-to-use-the-new-router-in-expressjs-4 有一篇很好的文章,它描述了路由器的区别以及可以做什么。

总结

使用路由器,您可以更轻松地模块化代码。您可以将路由器用作:

  1. 基本路线:首页、关于
  2. 路由中间件以将请求记录到控制台
  3. 带参数的路由
  4. 为参数路由中间件以验证特定参数
  5. 验证传递给特定路由的参数

注意:

在 Express 4 中删除的 app.router 对象在 Express 5 中卷土重来。在新版本中,它只是对基本 Express 路由器的引用,不像在 Express 3 中,应用程序具有显式加载它。

【讨论】:

    【解决方案3】:
    app.route('/book')
      .get(function (req, res) {
        res.send('Get a random book')
      })
      .post(function (req, res) {
        res.send('Post a random book')
      })
    

    如上例,我们可以在一个路由下添加不同的HTTP请求方法。

    【讨论】:

    • OP 询问的是express.Router,而不是app.route
    【解决方案4】:

    假设您的应用程序有点复杂。因此,我们首先要做的是将应用程序划分为多个模块,这样一个模块中的更改就不会使其他模块混乱,您可以继续处理单个模块,但归根结底,您需要将所有内容集成到一个模块中,因为您正在构建单个应用程序。就像我们有一个主应用程序和几个子应用程序,其父应用程序是主应用程序。 因此,当我们创建父应用程序时,我们使用

    var express = require('express');
    var parent = express();
    

    对于这个父应用程序,我们需要引入子应用程序。但是由于子应用程序不是完全不同的应用程序(因为它们在相同的上下文-java 术语中运行),express 提供了通过 Expresse 的 Router 函数来实现它的方法,这就是我们在每个子模块文件中所做的事情让我们称一个这样的子模块为 aboutme

    var express = require('express');
    var router = express.Router();
    /**
    ** do something here
    **/
    module.exports = router;
    

    通过 module.exports 我们使这个模块可供其他人使用,并且由于我们已经模块化了一些东西,我们需要通过节点的 require 函数使模块文件对父应用程序可用,就像任何其他第三方模块和父文件看起来像这样。

    var express = require('express') 
    var parent = express() 
    var child = require(./aboutme)
    

    在我们将这个子模块提供给父应用后,我们需要告诉父应用程序何时使用这个子应用程序。假设当用户点击关于我的路径时,我们需要关于我的子应用程序来处理请求,我们使用 Expresse 的 use 方法来完成。

    parent.use('/aboutme',  aboutme);
    

    在一张照片中,父文件看起来像这样

    var express = require('express');
    var parent = express();
    var child = require(./aboutme);
    /***
    **do some stuff here
    **/
    parent.use('/aboutme',child);
    

    最重要的是,父母可以做的是它可以启动一个服务器,而孩子却不能。希望这能澄清一下。有关更多信息,您可以随时查看源代码,这需要一些时间,但它为您提供了很多信息。谢谢。

    【讨论】:

    • 不应该是parent.use('/aboutme', child)吗?
    • 但是 child 能做什么而父母不能呢?为什么不将express() 用于主应用程序及其所有子应用程序?
    【解决方案5】:

    它们有何不同

    每个人,包括文档,都倾向于回顾它们有多少相同,但实际上并没有提及任何差异。嗯,事实上,它们是不同的。

    var bigApp = express();
    var miniApp = express.Router();
    

    听()

    最明显的区别是bigApp 将给出listen,这只是一种相当混乱的方式来完成节点httphttps 模块的操作:

    var server = require('http').createServer(bigApp);
    
    server.listen(8080, function () {
      console.info(server.address());  
    });
    

    我认为这是一种反模式,因为它首先抽象并掩盖了一些并不复杂或困难的东西,然后使人们难以使用 websockets 和其他需要原始 http 服务器的中间件。

    内部状态

    真正重要的最大区别是所有bigApps 都有独立的内部状态。

    bigApp.enable('trust proxy');
    bigApp.enabled('trust proxy');
    // true
    
    var bigApp2 = express();
    bigApp2.enabled('trust proxy');
    // false
    
    bigApp.use('/bunnies', bigApp2);
    // WRONG! '/bunnies' will NOT trust proxies
    

    但是,传递给 bigAppminiApp 将由 bigApp 操作,从而保留其内部状态和 thisness,并且这些路由将相应地运行。

    bigApp.enable('trust proxy');
    bigApp.enabled('trust proxy');
    // true
    
    var miniApp = express.Router();
    
    bigApp.use('/bunnies', miniApp);
    // CORRECT! All state and such are preserved
    

    这可能很重要,因为 expresshttp.ServerRequesthttpServerResponse 对象做了很多(有时是棘手的)事情 - 例如修改(或劫持)req.urlreq.originalUrl 以及其他各种您一直在使用而没有意识到的属性 - 您可能不希望重复和分离。

    更小的 API

    Router 可以使用的函数数量更少、定义更明确:

    • .use(mount, fn)
    • .all(mount, fn)
    • .options(mount, fn)
    • .head(mount, fn)
    • .get(mount, fn)
    • .post(mount, fn)
    • .patch(mount, fn)
    • .put(mount, fn)
    • .delete(mount, fn)
    • .route(mount).XXXX
    • .param(name, cb).XXXX

    还有一些其他方便的方法,例如basic(),但您不会找到set()enable() 或其他更改较大应用程序状态的方法。

    【讨论】:

      【解决方案6】:

      使用 app.js 编写路由意味着所有用户都可以访问它们,因为 app.js 在应用程序启动时加载。但是,将路由放入 express.router() 迷你应用程序会保护和限制它们的可访问性。

      【讨论】:

        【解决方案7】:

        总之express.Routerapp.get()可以做更多的事情,比如中间件,而且你可以用express.Router()多定义一个路由对象

        【讨论】:

          【解决方案8】:

          express.Router 有很多选择:

          • 启用区分大小写:/show 路由与/Show 不同,默认禁用此行为
          • 严格路由模式:/show/ 路由到与/show 不同,默认情况下也禁用此行为
          • 我们可以将特定的中间件添加到特定的路由中

          【讨论】:

            【解决方案9】:

            在测验中的一个问题中被问到:"express.Router() 创建一个行为类似于应用程序对象的对象。”

            正确答案是“对”。我知道我们都可以使用两者中的任何一个来创建路由器,但是可以肯定地说它们在所有情况下都不相同吗?如果我的理解是正确的,express() 变量可以做更多的事情,比如启动一个服务器,而另一个不能。

            【讨论】:

            • 这并不意味着它没有用,假设您要制作一个使用自己的api的应用程序。为一个 api 创建两个不同的服务器实际上是没有意义的。这可以通过路由有效地完成。
            【解决方案10】:

            在复杂的应用程序中,app 是模块,例如文章和用户。路由器是模块中的控制器或动作,例如文章创建和列表。 例如 url https://example.com/article/create 解析文章模块并创建路由器。

            app 和 router 也可以是层中层的。

            【讨论】:

              猜你喜欢
              • 2014-06-29
              • 2015-09-15
              • 2013-03-14
              • 1970-01-01
              • 2019-11-05
              • 1970-01-01
              • 2019-06-27
              • 1970-01-01
              相关资源
              最近更新 更多