Async Express中间件,它是如何知道的

时间:2016-09-25 13:32:59

标签: node.js express

所以我有我的Express(4.0)配置:

app.get('/api/tracks', (req, res) => {

});

在其中我想查询elasticsearch:

app.get('/api/tracks', (req, res) => {
    client.search({
        index: 'someindex',
        type: 'sometype',
        body: {
            query: {
                match_all: {}
            }
        }
    }, (err, resp) => {
        res.json(resp);
    });
});

这显然是" async"请求,因为回调情况。

Express如何知道在你发送内容之前一直闲逛,因为在所有的帐户中,response都可能在搜索完成后发出....(在ES请求之前的方式)完成)

如果Express使用某种类型的事件,那么调用res.end()之类的东西来表示响应的结束,为什么它不会在所有正常get&上执行此操作#39; s或post&#39}并让它们打开?

由于:

app.get('/api/profile', (req, res) => {
    res.json({ user: 'callum' });
});

正常工作,根据浏览器response已完成....

1 个答案:

答案 0 :(得分:1)

您只能res.json()执行一次。考虑这个例子:

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

app.get('/json1', function (req, res) {
  setTimeout(function () {
    res.json({ok:true});
  }, 2000);
});

app.get('/json2', function (req, res) {
  setTimeout(function () {
    res.json({ok:true});
    res.json({ok:true});
  }, 2000);
});

app.listen(3333);

使用以下方式访问时:

$ curl http://localhost:3333/json1

你在2秒后得到这个:

{"ok":true}

但是如果您尝试使用以下方式访问它:

curl http://localhost:3333/json2

然后你仍然可以在客户端得到这个:

{"ok":true}

但是您的服务器崩溃了:

_http_outgoing.js:344
    throw new Error('Can\'t set headers after they are sent.');
    ^

Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)

这意味着Express等待res.json()并在获得请求后立即完成请求,但在此之后您无法再次调用它。

res.send()也是如此 - 例如看到那些路线:

app.get('/send1', function (req, res) {
  setTimeout(function () {
    res.send('ok');
  }, 2000);
});

app.get('/send2', function (req, res) {
  setTimeout(function () {
    res.send('ok');
    res.send('ok');
  }, 2000);
});

另一方面,您似乎可以拨打res.end()两次,第二次通话会被忽略:

app.get('/end1', function (req, res) {
  setTimeout(function () {
    res.end('ok');
  }, 2000);
});

app.get('/end2', function (req, res) {
  setTimeout(function () {
    res.end('ok');
    res.end('ok');
  }, 2000);
});

但是如果您使用res.write()而不是res.end(),则请求将等待res.end()并且永远不会完成:

app.get('/end1', function (req, res) {
  setTimeout(function () {
    res.end('ok');
  }, 2000);
});

app.get('/end2', function (req, res) {
  setTimeout(function () {
    res.end('ok');
    res.end('ok');
  }, 2000);
});

但是消息实际上已经传递 - 您可以通过" \ n"结束消息来观察消息。让curl在到达时显示它:

app.get('/write1', function (req, res) {
  setTimeout(function () {
    res.write('ok\n');
  }, 2000);
});

app.get('/write2', function (req, res) {
  setTimeout(function () {
    res.write('ok\n');
    res.write('ok\n');
  }, 2000);
});

正如您所看到的,有一些方法可以发送数据 - 比如res.write()可以多次使用并且不会关闭连接。还有其他方法,如res.json(),只能使用一次,它们会隐式关闭连接。

但是如果你添加这样的路线:

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

然后Express会在连接打开的情况下永远等待,因为它无法判断将来是否会调用res.end()res.json()。它只能知道它是否已被调用。