Poste o corpo em Node.js e alguma verificação de condição assíncrona
-
25-09-2019 - |
Pergunta
Eu quero obter solicitação (postar) corpo de http.ServerRequest
, mas não faça isso reto quando minha função de solicitação é chamada, mas somente depois de algum tempo (Redis Query).
Eu tenho um exemplo muito simples para ilustrar:
var http = require('http'),
sys = require('sys');
http.createServer(function (req, res) {
sys.puts("Got request");
req.pause();
setTimeout(function() { // In real code I'm accessing Redis here.
var body = "";
req.addListener('data', function (chunk) {
sys.puts("Got 'data' event");
body += chunk;
});
req.addListener('end', function () {
sys.puts("Got 'end' event");
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(body);
});
req.resume();
}, 10);
}).listen(8000);
Neste exemplo data
e end
Os eventos são completamente perdidos, mesmo que eu esteja ligando req.pause()
/req.resume()
, então o pedido está "preso".
Se eu comentar setTimeout()
Ligue e faça tudo diretamente na função de solicitação, tudo funciona conforme o esperado. Mas quero consultar o Redis para ver sempre que a solicitação é válida. As postagens são grandes uploads de arquivo e não quero perder tempo esperando o upload malsucedido será concluído.
A maneira simples de fazer isso é adiar o post para alguns milissegundos (no meu caso, as postagens levariam pelo menos vários segundos, portanto, esse pequeno atraso é bastante insignificante). O mais intenso é começar a analisar dados de entrada, validando simultaneamente a solicitação e soltar a conexão se a solicitação for considerada inválida.
A questão é: como eu faria nada disso? Estou usando o Node.js versão 0.1.97-14-G0055DD1 se isso importa.
Obrigado por quaisquer sugestões.
Solução
Não sei sempre que estou fazendo isso direito, mas isso parece certo para mim:
var http = require('http'),
sys = require('sys');
http.createServer(function (req, res) {
var body = "",
body_complete = false,
wait_complete = false;
sys.debug("Got request");
// This will be called on each process' completion
var final_cb = function(err) {
if (err) throw new Error(err);
if (body_complete && wait_complete) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(body);
}
};
// Async process one: get POST body
req.addListener('data', function (chunk) {
sys.debug("Got 'data' event");
body += chunk;
});
req.addListener('end', function () {
sys.debug("Got 'end' event");
body_complete = true;
final_cb(null)
});
// Async process two: wait 10ms
setTimeout(function() { // In real code I'm accessing Redis here.
sys.debug("Timeout passed");
if (false) { // Okay, timeout can't go wrong
res.writeHead(403);
res.end('Sorry');
}
wait_complete = true;
final_cb(null);
}, 10);
}).listen(8000);
Adição: Quando o Connect Middleware deseja executar algumas solicitações assínconas (ou seja, o controle de passe de volta ao loop do evento), ele funciona dessa maneira:
var pause = utils.pause(req);
fs.readFile(path, function(){
next();
pause.resume();
});
Onde utils.pause()
é um hack para buffer eventos pendentes.