我试图从url列表中下载一些文件,但我不想下载超过一定大小的文件(比如1MB)。这些文件可能是千兆字节,所以我需要一种方法,在响应流增长到大于1MB时立即取消下载。

let request = require("request");
function getFile(url, callback) {
  request.get(url)
  .on('response', function(response) {
    let output = "";
    response.on('data', function(chunk) {
      if(output.length > 1000000) {
        // ??? ABORT STREAM HERE ???
        console.log(`${url} is too big`);
        callback(true);
      } else {
        output += chunk.toString("utf8");
      }
    });
    response.on('end', function() {
      console.log(`${url} download complete`);
      callback(null, output);
    });
  });
}

我不知道该怎么做。This github issue for the request library讨论了中止请求,但我认为我想中止实际的http响应流,而不是请求。有人问了一个类似的问题,但回答者似乎认为这是不可能的。我确信这不是真的(或者我误解了他们的答案),否则我会被迫下载我遇到的每一个10gig文件。
它是否与删除dataend事件侦听器一样简单?直觉上,我猜下载会继续,不管是否附加了事件,但我真的不知道它是如何在幕后工作的。谢谢你的帮助!

最佳答案

我对此做了更多的讨论,结果发现request包的.abort()方法确实取消了http响应流。
我希望有一种更通用的方法来取消不依赖于请求包的http响应流,但这对我的目的是可行的,因为我目前正在使用请求库。

let request = require("request");

function getFile(url, callback) {
  let tooBig = false;
  let r = request.get(url)
    .on('error', callback)
    .on('response', function(response) {
      let output = "";
      response.on('error', function(error) {
        callback(error, null);
      });
      response.on('data', function(chunk) {
        if(output.length > 1000000) {
          tooBig = true;
          r.abort();
        } else {
          output += chunk.toString("utf8");
        }
      });
      response.on('end', function() {
        if(tooBig) {
          console.log(`${url} was too big`);
          callback("too big", null);
        } else {
          console.log(`${url} download complete`);
          callback(null, output);
        }
      });
    });
}

另外,如果您使用的是请求库,那么事情可以简化一些:
function getFileSimplified(url, callback) {
  let output = "";
  let tooBig = false;
  let r = request.get(url)
    .on('error', callback)
    .on('data', function(chunk) {
      if(output.length > 1000000) {
        tooBig = true;
        r.abort();
      } else {
        output += chunk.toString("utf8");
      }
    })
    .on('end', function() {
      if(tooBig) {
        console.log(`${url} was too big`);
        callback("too big", null);
      } else {
        console.log(`${url} download complete`);
        callback(null, output);
      }
    })
}

希望对遇到类似问题的人有所帮助。我不会接受这个答案,因为问题的正确答案不应该依赖于npm请求包。如果有人知道怎么做,请再发一个答案,我会接受的。

09-19 12:21