nodejs – 如何promisify http.request? 拒绝被叫了两次

我试图把http.request包装到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); }); 

如果我从远程服务器收到错误的statusCode ,它会调用First reject并在一段时间之后第二次拒绝 。 如何正确地做,所以它只调用一个拒绝(我认为在这种情况下, 首先拒绝是适当的)? 我想我需要自己closuresres ,但ClientResponse对象上没有close()方法。

UPD:第二次拒绝很less触发 – 为什么?

你的代码几乎没有问题。 稍微重申一下,你需要一个以这种forms包装http.request的函数:

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

注意paramspostData的添加,所以这可以用作一个通用的请求。 并注意最后一行 req.end() – 必须始终被调用 – 从OP代码中丢失。

将这些情侣变化应用到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(); }); } 

这是未经testing,但它应该工作正常…

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

而且这些承诺也可以链接在一起

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

你可以使用蓝鸟api更容易,你可以promisify请求模块,并使用asynchronous请求函数作为承诺本身,或者你可以select使用模块request-promise ,这使得你不能创build一个承诺,但使用和使用promise已经封装模块的对象,这里是一个例子:

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