hap*_*set 39 httprequest node.js 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);
});
Run Code Online (Sandbox Code Playgroud)
如果我statusCode从远程服务器接收到错误,它将调用第一次拒绝,并在一段时间后第二次拒绝.如何正确使它只调用单一拒绝(我认为在这种情况下,首先拒绝是正确的)?我想我需要关闭res自己,但对象close()上没有方法ClientResponse.
UPD: 第二次拒绝很少触发 - 为什么?
dan*_*anh 60
你的代码几乎没问题.要重做一点,你需要一个用这个表单包装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()
});
}
Run Code Online (Sandbox Code Playgroud)
注意加入的params和postData所以这可以用作一个通用的请求. 并注意 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();
});
}
Run Code Online (Sandbox Code Playgroud)
这是未经测试的,但应该可以正常工作......
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);
});
Run Code Online (Sandbox Code Playgroud)
这些承诺也可以链接......
httpRequest(params).then(function(body) {
console.log(body);
return httpRequest(otherParams);
}).then(function(body) {
console.log(body);
// and so on
});
Run Code Online (Sandbox Code Playgroud)
Dee*_*pak 11
还有其他方法,但在这里您可以找到一种简单的方法将 http.request 设为 promise 或 async/await 类型。
这是一个工作示例代码:
var http = require('http');
function requestAsync(name) {
return new Promise((resolve, reject) => {
var post_options = {
host: 'restcountries.eu',
port: '80',
path: `/rest/v2/name/${name}`,
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
let post_req = http.request(post_options, (res) => {
res.setEncoding('utf8');
res.on('data', (chunk) => {
resolve(chunk);
});
res.on("error", (err) => {
reject(err);
});
});
post_req.write('test');
post_req.end();
});
}
//Calling request function
//:1- as promise
requestAsync("india").then(countryDetails => {
console.log(countryDetails);
}).catch((err) => {
console.log(err);
});
//:2- as await
let countryDetails = await requestAsync("india");
Run Code Online (Sandbox Code Playgroud)
我知道这个问题很旧,但是答案实际上激发了我编写轻量级承诺HTTP客户端的现代版本。这是一个新版本:
代码如下:
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();
});
}
Run Code Online (Sandbox Code Playgroud)
阅读所有这些文章和几篇文章后,我想我应该发布一种处理 http 和 https 的“通用”解决方案:
const http = require("http");
const https = require("https");
const url_obj = require("url");
const request = async (url_string, method = "GET", postData = null) => {
const url = url_obj.parse(url_string);
const lib = url.protocol=="https:" ? https : http;
const params = {
method:method,
host:url.host,
port: url.port || url.protocol=="https:" ? 443 : 80,
path: url.path || "/"
};
return new Promise((resolve, reject) => {
const req = lib.request(params, res => {
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error(`Status Code: ${res.statusCode}`));
}
const data = [];
res.on("data", chunk => {
data.push(chunk);
});
res.on("end", () => resolve(Buffer.concat(data).toString()));
});
req.on("error", reject);
if (postData) {
req.write(postData);
}
req.end();
});
}
Run Code Online (Sandbox Code Playgroud)
你可以这样使用:
request("google.com").then(res => console.log(res)).catch(err => console.log(err))
Run Code Online (Sandbox Code Playgroud)
这很大程度上受到本文的启发,但用内置的 api 替换了 hacky url 解析。
Fer*_*rin -4
使用 bluebird api 更容易,您可以promisify request 模块并使用 request 函数 async 作为 Promise 本身,或者您可以选择使用模块request-promise,这使您不必创建 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...
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
31334 次 |
| 最近记录: |