nodejs-como promisificar http.pedido? o reject foi chamado duas vezes.

Estou a tentar embrulhar ... Promise:

 new Promise(function(resolve, reject) {
    var req = http.request({
        host: '127.0.0.1',
        port: 4000,
        method: 'GET',
        path: '/api/v1/service'
    }, function(res) {
        if (res.statusCode < 200 || res.statusCode >= 300) {
            // First reject
            reject(new Error('statusCode=' + res.statusCode));
            return;
        }
        var body = [];
        res.on('data', function(chunk) {
            body.push(chunk);
        });
        res.on('end', function() {
            try {
                body = JSON.parse(Buffer.concat(body).toString());
            } catch(e) {
                reject(e);
                return;
            }
            resolve(body);
        });
    });
    req.on('error', function(err) {
        // Second reject
        reject(err);
    });
    req.write('test');
}).then(function(data) {
    console.log(data);
}).catch(function(err) {
    console.log(err);
});

Se Eu receber errornous {[[3]} do servidor remoto ele vai chamar primeiro rejeitar e depois de um pouco de tempo segundo rejeitar. Como fazer corretamente para que ele chame apenas um único rejeitado (eu acho que primeiro rejeitar é um adequado neste caso)? Acho que preciso de me fechar, mas não há nenhum método em ClientResponse objecto.

UPD: A segunda rejeição desencadeia muito raramente-porquê?

Author: happy_marmoset, 2016-07-22

2 answers

O teu código está quase bom. Para reafirmar um pouco, você quer uma função que envolve http.pedido com este formulário:
function httpRequest(params, postData) {
    return new Promise(function(resolve, reject) {
        var req = http.request(params, function(res) {
            // on bad status, reject
            // on response data, cumulate it
            // on end, parse and resolve
        });
        // on request error, reject
        // if there's post data, write it to the request
        // important: end the request req.end()
    });
}

Note a adição de params e postData para que este possa ser usado como um pedido de propósito geral. E reparem na última linha. req.end() -- o que deve ser sempre chamado ... estava desaparecido do código de operação.

Aplicar essas alterações ao código de operação...

function httpRequest(params, postData) {
    return new Promise(function(resolve, reject) {
        var req = http.request(params, function(res) {
            // reject on bad status
            if (res.statusCode < 200 || res.statusCode >= 300) {
                return reject(new Error('statusCode=' + res.statusCode));
            }
            // cumulate data
            var body = [];
            res.on('data', function(chunk) {
                body.push(chunk);
            });
            // resolve on end
            res.on('end', function() {
                try {
                    body = JSON.parse(Buffer.concat(body).toString());
                } catch(e) {
                    reject(e);
                }
                resolve(body);
            });
        });
        // reject on request error
        req.on('error', function(err) {
            // This is not a "Second reject", just a different sort of failure
            reject(err);
        });
        if (postData) {
            req.write(postData);
        }
        // IMPORTANT
        req.end();
    });
}
Isto não foi testado, mas deve funcionar bem...
var params = {
    host: '127.0.0.1',
    port: 4000,
    method: 'GET',
    path: '/api/v1/service'
};
// this is a get, so there's no post data

httpRequest(params).then(function(body) {
    console.log(body);
});
E estas promessas podem fica acorrentado, também...
httpRequest(params).then(function(body) {
    console.log(body);
    return httpRequest(otherParams);
}).then(function(body) {
    console.log(body);
    // and so on
});
 32
Author: danh, 2017-05-30 21:46:07

É mais fácil para você usar bluebird api, você pode promisify módulo de solicitação e usar a função de pedido assíncrono como uma promessa a si mesmo, ou você tem a opção de utilizar o módulo pedido-promessa, que faz com que você não trabalhar para a criação de uma promessa, mas usando e objeto que já encapsula o módulo usando promessa, aqui está um exemplo:

var rp = require('request-promise');

rp({host: '127.0.0.1',
    port: 4000,
    method: 'GET',
    path: '/api/v1/service'})
    .then(function (parsedBody) {
        // GET succeeded... 
    })
    .catch(function (err) {
        // GET failed... 
    });
 -2
Author: Fernando Zamperin, 2016-07-22 19:07:33