2016-09-25 5 views
0

Так у меня есть 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); 
    }); 
}); 

Это явно «асинхронной» запрос из-за ситуации обратного вызова.

Как Экспресс знать торчать, пока вы отправить что-то, потому что, судя по всему, то response мог быть разослан, когда поиск закончил выполнение .... (путь до того, как запрос ES кончила)

Если Экспресс использует как какое-то использование событий, так что называя что-то вроде res.end(), чтобы сигнализировать о конце ответа, почему он этого не делает на всех нормальных get или post и оставить их открытыми?

Потому что:

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

работает нормально и response согласно браузер закончил ....

ответ

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 

Тогда вы все равно получите это на своем 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); 
}); 

Но сообщение на самом деле доставляется - что у НУ может наблюдать, прекратив сообщение от «\ п», чтобы сделать 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

Таким образом, соединение поддерживается открытым до тех пор, –

+0

@CallumLinington Да. Но для тайм-аута (на стороне Express) вам нужно использовать промежуточное ПО, например 'connect-timeout', с' var timeout = require ('connect-timeout'); app.use (timeout ('5s')); 'или что-то в этом роде. В противном случае Express будет ожидать, вероятно, тайм-аута на стороне клиента или таймаута TCP-соединения. – rsp

+0

О да, это жемчужина! –