[英]Async Express middleware, how does it know
所以我有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);
});
});
由於回調情況,這顯然是一個“異步”請求。
Express如何知道一直待在您發送東西之前,因為從所有帳戶來看, response
可能是在搜索完成執行后發出的...。(在ES請求完成之前)
如果Express使用類似事件的用法,那么調用res.end()
這樣的信號來表示響應結束,為什么它不對所有正常的get
或post
這樣做並保持打開狀態?
因為:
app.get('/api/profile', (req, res) => {
res.json({ user: 'callum' });
});
正常工作,並且根據瀏覽器的response
已完成。
您只能執行一次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.end()
或res.json()
。 它只能知道它是否已經被調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.