如何在Node.js中正确取消http请求?

How to cancel http request properly in Node.js?

我需要在 Node.js 中实现可取消的客户端 HTTP 请求,而不使用外部库。我给出了一个 Promise 对象 - cancellationPromise - 当外部请求取消时它会被拒绝。这就是我知道我可能需要打电话给 request.abort() 的方式。

问题是,只有当 https.request 仍未决并且 response 对象尚不可用时,我才应该调用 request.abort() 吗?

或者,即使我已经获得 response 对象并正在处理响应数据,我是否也应该调用它,如下面的代码所示?在这种情况下,这会阻止更多 response.on('data') 事件的发生吗?

  async simpleHttpRequest(url, oauthToken, cancellationPromise) {
    let cancelled = null;
    let oncancel = null;

    cancellationPromise.catch(error => { 
      cancelled = error; oncancel && oncancel(error) });

    try {
      const response = await new Promise((resolve, reject) => {
        const request = https.request(
          url.toString(), 
          { 
            method: 'GET', 
            headers: { 'Authorization': `Bearer ${oauthToken}` }        
          }, 
          resolve);

        oncancel = error => request.abort();
        request.on('error', reject);
        request.end();
      });

      if (cancelled) throw cancelled;

      // do I need "oncancel = null" here?
      // or should I still allow to call request.abort() while fetching the response's data?

      // oncancel = null;

      try {
        // read the response 
        const chunks = await new Promise((resolve, reject) => {
          response.on('error', reject);  
          const chunks = [];
          response.on('data', data => chunks.push(data));
          response.on('end', () => resolve(chunks));
        });

        if (cancelled) throw cancelled;
        const data = JSON.parse(chunks.join(''));
        return data;
      }
      finally {
        response.resume();
      }
    }
    finally {
      oncancel = null;
    }
  }

这取决于您希望通过中止请求实现什么。

只是一些背景知识。 HTTP 1 无法 "cancel" 它发送请求然后等待响应。您不能 "roll back" 您所做的请求。您需要一个分布式事务来这样做。 (Further reading.) As the MDN developer document states:

The XMLHttpRequest.abort() method aborts the request if it has already been sent. When a request is aborted, its readyState is changed to XMLHttpRequest.UNSENT (0) and the request's status code is set to 0.

基本上,您阻止响应被您的应用程序处理。其他应用程序可能(如果您在发送给它后调用 abort())无论如何都会完成处理。

从问题的角度来看:

The question is, should I be calling request.abort() only if https.request is still pending and response object is not yet available?

TL.DR.: 仅从您的应用程序的角度来看才重要。当我浏览您的代码时,我认为它可以正常工作。