异步快递中间件,它是如何知道

异步快递中间件,它是如何知道

问题描述:

所以,我有我的快递(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); 
    }); 
}); 

这显然是一个“异步”因回调情况而提出要求。

如何快速知道流连,直到你送东西,因为所有帐户,该response可能已发出时,搜索已经执行完毕....(前路的ES请求过完)

如果Express使用类似于某种事件的用法,所以调用类似res.end()的信号来表示响应结束,为什么它不会在所有正常的getpost上做这些事情并将它们保持打开状态?

因为:

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

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

你可以做res.json()只有一次。考虑下面这个例子:

$ curl http://localhost:3333/json1 

你2秒后得到这样的::

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); 

当你访问它

{"ok":true} 

但是,如果你试图用访问:

curl http://localhost:3333/json2 

然后你仍然得到这个在你的c lient方:

{"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) 

这意味着,快递等待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); 
}); 

但该消息实际上被交付 - 其中Y OU可以通过“\ 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) { 
}); 

然后快速将永远开放的连接等待,因为它没有办法知道是否res.end()res.json()将在未来被调用。它只能知道它是否已被调用。

+0

所以基本上,连接保持打开状态,直到你在'response'上发送''或'json'的东西或超时。 –

+0

@CallumLinington是的。但是对于超时(在Express方面),你必须使用一个像'connect-timeout'这样的中间件,其中'var timeout = require('connect-timeout'); app.use(timeout('5s'));'或者类似的东西。否则Express将等待客户端的超时或TCP连接的超时。 – rsp

+0

哦,对,那是一颗宝石! –