nodejs - 如何承诺 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 并在一段时间后调用 Second reject 。如何正确制作,使其仅调用一次拒绝(我认为在这种情况下, 第一次拒绝 是正确的)?我想我需要自己关闭 res ,但是在 ClientResponse 对象上没有 close() 方法。

UPD: 很少触发第二次拒绝 - 为什么?

原文由 happy_marmoset 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 309
1 个回答

在阅读了所有这些和几篇文章之后,我想我会发布一种同时处理 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();
  });
}

你可以这样使用:

 request("google.com").then(res => console.log(res)).catch(err => console.log(err))

这在很大程度上受到了 这篇文章 的启发,但是用内置的 api 替换了 hacky url 解析。

原文由 ThisGuyCantEven 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题