在Node.js和Node中间件中,'req'和'res'参数分别代表什么?

5

我对Node和Express以及与使用node构建Web应用程序相关的其他层次都很陌生,requestresponse参数让我感到非常困惑。我的困惑在于这两个参数经常出现在一个函数中,但有时一个或两个参数没有被声明。此外,大部分时间会抛出另一个参数,比如'next'或其他东西。例如,我有以下API路由器:

router.route('/teams')
    // create a team at POST http://localhost:8080/api/teams
    .post(function(req, res) {
        var team = new Team();
        team.name = req.body.name;
        team.location = req.body.location;

        // save the new team and check for errors
        team.save(function(err) {
            if (err) {
                res.send(err);
            };
            res.json({ message: 'Team created!' });
        }); 
    })
    // GET all the teams at GET http://localhost:8080/api/teams
    .get(function(req, res) {
        Team.find(function(err, teams){
            if (err) {
                res.send(err);
            };
            res.json(teams);
        });
    });

.post.get 都调用一个带有 reqres 参数的函数,但是 req 从未被使用。如果它们没有被定义或不按完全不同的顺序使用或根本不使用,函数如何知道如何处理 req 或 res?或者如果我将它们命名为完全不同的名称呢?

请求和响应到底发生了什么?对不起我的无知。我已经阅读了文档,但还是没明白。

谢谢。


1
它们是来自http://nodejs.org/api/http.html#http_event_request的`请求(request)`和`响应(response)`。 - Jonathan Lonowski
3个回答

7
当你使用expressApp.use('/some/route', myRouteHandler);时,Express将监听该路由的请求,当它被访问时,它将调用你提供的函数(回调函数)。它会给它三个参数:请求和响应以及下一个(next)。(实际上可能是四个,但让我们保持简单。)
因此,你的回调函数可能像这样定义:
function myRouteHandler(a, b, c) {
    // do stuff
};

或者像这样:
function myRouteHandler(req, res, next) {
    // stuff
}

或简单地说:
function myRouteHandler() {
    // stuff
}

无论你做什么都没关系。当应用程序启动时,express会监听请求。
当其中一个匹配路由(/some/route)时,express将在内部调用您提供的函数,就像这样:
myRouteHandler(requestObject, responseObject, nextMiddleware);

在第一个情况下,您可以通过使用req来访问请求(例如,请求标头、完整的url、调用者IP地址或类似内容)。在第二种情况下,您将通过调用a来访问它。在第三种情况下,您可以使用arguments[0]。
按照惯例,人们会使用以下形式:myCallback(req, res),并知道Express会将请求对象作为第一个参数,响应作为第二个参数。实际上,响应对象有一个end()方法,因此您可以结束请求。如果还有next()对象,您可以调用下一个中间件。
假设您定义了如下路由:
app.use('/api/users', checkAuthorizationHandler);
app.use('/api/users', makeSureTheIPisFromOurInternalNetwork);
app.use('/api/users', nowHandleTheResponse);

每个处理程序都有第三个参数。如果您命名它,通常在函数声明中称之为“下一个”参数。这意味着按顺序的下一个函数。
假设您的 `function checkAuthorizationHandler(req, res, next)` 将检查 `req.headers('auth')` 令牌是否正确,如果正确,则在函数体中调用 `next()`。
然后调用 `function makeSureTheIPisFromOurInternalNetwork(a, b, c)`。它将检查 `a.ip` 是否是 LAN IP 地址,并调用 `c();`。
最后,`function nowHandleTheResponse()` 将找到所有用户,并使用用户的 JSON 对象进行响应: `arguments[1].json([user1, user2, user3]);`
因此,第一个参数是 express 给您的内容,它是请求,第二个是响应,第三个是下一个中间件函数。无论您如何称呼它们,它们都在那里。
P.S. 您还可以使用四个参数声明自己的中间件。
function(error, req, res, next);

Express将会检查你的函数,如果发现你有四个参数而不是两个或三个,它将给你任何在中间件链中运行的错误。这意味着,如果你的checkAuthHandler说next(new Error('Not authorized'));,那么你的下一个函数可能会检查该错误,如果存在,则不会给出结果。通常情况下,检测到错误的中间件只会res.end('some error message');
如果我还没有让你困惑,那就告诉我,我还有更多类似的内容 :)

非常感谢您提供的精彩答案!这解决了很多问题。如果您有更多的时间,您能否用儿童语言解释一下我在问题中发布的.post(function(req, res)函数中正在发生的事情?.body是从哪里来的,它何时可用?非常感谢。 - reknirt
1
.post 基本上是您 POST 到 URL 的任何内容。我会用更多的例子更新答案 :) - Zlatko

4
这是一个框架约定。第一个参数是“请求”(request),第二个参数是“响应”(response)。如果您声明了中间件(.use),则第三个参数是链中的下一个中间件(next)。
您可以随意命名这些变量,只要知道它们的顺序即可。例如:.post(function(a,b) {});,请求由变量a表示,响应由变量b表示。
如果出于某种原因,您不需要请求,只需要响应,则仍然必须有第一个参数,因为响应由第二个参数表示。
在JavaScript中,没有像Java那样的方法重载(也许这就是您混淆的地方)。函数由其名称表示,而不是它所需的参数数目。以下是一个简单的例子:
function logToConsole(level, message) {
  if (!message) {
    message = level;
    level = 'INFO';
  }
  console.log('['+level+']', message);
}

logToConsole('My message'); // prints out: "[INFO] My message"
logToConsole('WARN', 'My message'); // prints out: "[WARN] My message"

你有没有注意到我们如何基于message的存在定义了level的默认值?
希望这能让事情更清楚一些。

顺便说一下,您的 req 变量用于在 .post 中获取发送的正文。 - gtramontina

1

Request(请求)、response(响应)和next(下一个)参数会传递给所有中间件函数。 request对象包含有关HTTP request的信息,而response对象用于处理requestExpressjs documentation详细介绍了这些对象。在调度程序中使用next()调用,中间件函数可能会或可能不会调用next(),具体取决于用法。 Next只是简单地调用以下中间件。

以下是使用next()的示例:

function helloWorld(req,res,next){

     console.log('Hello, world!');
     next();
}

// This function doesn't call next(), therefore it will 
// not call the subsequent middleware in the dispatcher
function goodbyeWorld(req,res,next){
     console.log('Goodbye, world!');
}

app.use(helloWorld);
app.use(goodbyeWorld);

输出:

你好,世界!

再见,世界!

现在让我们重新排序中间件。

app.use(goodbyeWorld);
app.use(helloWorld);

输出:

再见,世界!

helloWorld 函数未被调用。注意中间件顺序和 next() 函数的重要性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接