nodejs node make example node.js promise httprequest

node.js - make - nodejs http server



nodejs-¿Cómo promisificar http.request? rechazo fue llamado dos veces (3)

Estoy tratando de envolver http.request en 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); });

Si recibo un statusCode estado statusCode del servidor remoto, llamará Primero rechazar y después de un poco de tiempo Segundo rechazo . ¿Cómo hacer correctamente para que solo llame a un solo rechazo (creo que el primer rechazo es correcto en este caso)? Creo que necesito cerrar los res , pero no hay close() método close() en el objeto ClientResponse .

UPD: El segundo rechazo se dispara muy raramente, ¿por qué?


Es más fácil para usted usar bluebird api, puede promisify módulo de solicitud y usar la función de solicitud async como una promesa en sí misma, o tiene la opción de usar el módulo request-promise , que hace que no trabaje para crear una promesa sino que use y el objeto que ya encapsula el módulo usando la promesa, aquí hay un ejemplo:

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


Sé que esta pregunta es antigua, pero la respuesta me inspiró a escribir una versión moderna de un cliente HTTP ligero y prometido. Aquí hay una nueva versión que:

  • Utilice la sintaxis de JavaScript actualizada
  • Validar entrada
  • Soporta múltiples métodos
  • Es fácil de ampliar para el soporte HTTPS
  • Permitirá que el cliente decida cómo tratar con los códigos de respuesta
  • También permitirá que el cliente decida cómo tratar con cuerpos que no son JSON

Código abajo:

function httpRequest(method, url, body = null) { if (![''get'', ''post'', ''head''].includes(method)) { throw new Error(`Invalid method: ${method}`); } let urlObject; try { urlObject = new URL(url); } catch (error) { throw new Error(`Invalid url ${url}`); } if (body && method !== ''post'') { throw new Error(`Invalid use of the body parameter while using the ${method.toUpperCase()} method.`); } let options = { method: method.toUpperCase(), hostname: urlObject.hostname, port: urlObject.port, path: urlObject.pathname }; if (body) { options.headers[''Content-Length''] = Buffer.byteLength(body); } return new Promise((resolve, reject) => { const clientRequest = http.request(options, incomingMessage => { // Response object. let response = { statusCode: incomingMessage.statusCode, headers: incomingMessage.headers, body: [] }; // Collect response body data. incomingMessage.on(''data'', chunk => { response.body.push(chunk); }); // Resolve on end. incomingMessage.on(''end'', () => { if (response.body.length) { response.body = response.body.join(); try { response.body = JSON.parse(response.body); } catch (error) { // Silently fail if response is not JSON. } } resolve(response); }); }); // Reject on request error. clientRequest.on(''error'', error => { reject(error); }); // Write request body if present. if (body) { clientRequest.write(body); } // Close HTTP connection. clientRequest.end(); }); }


Tu código está casi bien. Para reformular un poco, desea una función que envuelva http.request con este formulario:

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

Observe la adición de params y postData para que se pueda utilizar como una solicitud de propósito general. Y observe que la última línea req.end() , que siempre debe llamarse, faltaba del código OP.

Aplicando esos cambios de pareja al código OP ...

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

Esto no se ha probado, pero debería funcionar bien ...

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

Y estas promesas pueden ser encadenadas, también ...

httpRequest(params).then(function(body) { console.log(body); return httpRequest(otherParams); }).then(function(body) { console.log(body); // and so on });