node.js nodejs - 如何承诺 http.request?拒绝被叫了两次
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38533580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
nodejs - How to promisify http.request? reject got called two times
提问by happy_marmoset
I'm trying to wrap http.requestinto Promise:
我试图包装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);
});
If I recieve errornous statusCodefrom remote server it will call First rejectand after a bit of time Second reject. How to make properly so it calls only single reject (I think First rejectis proper one in this case)? I think I need to close resmyself, but there is no close()method on ClientResponseobject.
如果我statusCode从远程服务器收到 errornous ,它将调用First reject并在一段时间后调用Second reject。如何正确制作以便它只调用单个拒绝(我认为在这种情况下第一个拒绝是正确的)?我想我需要关闭res自己,但是对象close()上没有方法ClientResponse。
UPD:Second reject triggers very rarely - why?
UPD:第二次拒绝触发很少 - 为什么?
回答by danh
Your code is almost fine. To restate a little, you want a function that wraps http.request with this form:
你的代码几乎没问题。重申一下,您需要一个用这种形式包装 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()
});
}
Notice the addition of paramsand postDataso this can be used as a general purpose request. And notice the last linereq.end()-- which must always be called -- was missing from the OP code.
请注意添加了等params,postData因此可以将其用作通用请求。 并注意最后一行req.end()——必须始终被调用——在 OP 代码中丢失了。
Applying those couple changes to the OP code...
将这些更改应用于 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();
});
}
This is untested, but it should work fine...
这是未经测试的,但它应该可以正常工作......
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);
});
And these promises can be chained, too...
这些承诺也可以被链接起来......
httpRequest(params).then(function(body) {
console.log(body);
return httpRequest(otherParams);
}).then(function(body) {
console.log(body);
// and so on
});
回答by Nicolas Bouvrette
I know this question is old but the answer actually inspired me to write a modern version of a lightweight promisified HTTP client. Here is a new version that:
我知道这个问题很老,但答案实际上激发了我编写轻量级 promisified HTTP 客户端的现代版本。这是一个新版本:
- Use up to date JavaScript syntax
- Validate input
- Support multiple methods
- Is easy to extend for HTTPS support
- Will let the client decide on how to deal with response codes
- Will also let the client decided on how to deal with non-JSON bodies
- 使用最新的 JavaScript 语法
- 验证输入
- 支持多种方式
- 易于扩展以支持 HTTPS
- 会让客户端决定如何处理响应代码
- 也会让客户端决定如何处理非JSON主体
Code below:
代码如下:
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();
});
}
回答by Binh Ho
Hope this help.
希望这有帮助。
const request = require('request');
async function getRequest() {
const options = {
url: 'http://example.com',
headers: {
'Authorization': 'Bearer xxx'
}
};
return new Promise((resolve, reject) => {
return request(options, (error, response, body) => {
if (!error && response.statusCode == 200) {
const json = JSON.parse(body);
return resolve(json);
} else {
return reject(error);
}
});
})
}
回答by Fernando Zamperin
It's easier for you to use bluebird api, you can promisifyrequest module and use the request function async as a promise itself, or you have the option of using the module request-promise, that makes you to not working to creating a promise but using and object that already encapsulates the module using promise, here's an example:
使用 bluebird api 对您来说更容易,您可以承诺请求模块并使用请求函数 async 作为承诺本身,或者您可以选择使用模块request-promise,这使您不必努力创建承诺而是使用和已经使用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...
});

