如何在不使用第三方库的情况下使用Node.js 下载文件?
我不需要什么特别的。我只想从给定的 URL 下载文件,然后将其保存到给定的目录。
如何在不使用第三方库的情况下使用Node.js 下载文件?
我不需要什么特别的。我只想从给定的 URL 下载文件,然后将其保存到给定的目录。
您可以创建一个 HTTPGET请求并将其response通过管道传输到一个可写的文件流中:
const http = require('http'); // or 'https' for https:// URLs
const fs = require('fs');
const file = fs.createWriteStream("file.jpg");
const request = http.get("http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg", function(response) {
  response.pipe(file);
});
如果你想支持在命令行上收集信息——比如指定目标文件或目录,或者 URL——检查像Commander这样的东西。
不要忘记处理错误!以下代码基于 Augusto Roman 的回答。
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
  var file = fs.createWriteStream(dest);
  var request = http.get(url, function(response) {
    response.pipe(file);
    file.on('finish', function() {
      file.close(cb);  // close() is async, call cb after close completes.
    });
  }).on('error', function(err) { // Handle errors
    fs.unlink(dest); // Delete the file async. (But we don't check the result)
    if (cb) cb(err.message);
  });
};
正如 Michelle Tilley 所说,但使用适当的控制流程:
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
  var file = fs.createWriteStream(dest);
  http.get(url, function(response) {
    response.pipe(file);
    file.on('finish', function() {
      file.close(cb);
    });
  });
}
如果不等待finish事件,幼稚的脚本可能会以不完整的文件结束。
编辑:感谢@Augusto Roman 指出cb应该传递给file.close,而不是显式调用。
说到处理错误,听请求错误甚至更好。我什至会通过检查响应代码来验证。这里仅对 200 响应代码认为成功,但其他代码可能很好。
const fs = require('fs');
const http = require('http');
const download = (url, dest, cb) => {
    const file = fs.createWriteStream(dest);
    const request = http.get(url, (response) => {
        // check if response is success
        if (response.statusCode !== 200) {
            return cb('Response status was ' + response.statusCode);
        }
        response.pipe(file);
    });
    // close() is async, call cb after close completes
    file.on('finish', () => file.close(cb));
    // check for request error too
    request.on('error', (err) => {
        fs.unlink(dest);
        return cb(err.message);
    });
    file.on('error', (err) => { // Handle errors
        fs.unlink(dest); // Delete the file async. (But we don't check the result) 
        return cb(err.message);
    });
};
尽管这段代码相对简单,我还是建议使用request module,因为它可以处理更多的协议(你好 HTTPS!),而http.
这样做会像这样:
const fs = require('fs');
const request = require('request');
const download = (url, dest, cb) => {
    const file = fs.createWriteStream(dest);
    const sendReq = request.get(url);
    // verify response code
    sendReq.on('response', (response) => {
        if (response.statusCode !== 200) {
            return cb('Response status was ' + response.statusCode);
        }
        sendReq.pipe(file);
    });
    // close() is async, call cb after close completes
    file.on('finish', () => file.close(cb));
    // check for request errors
    sendReq.on('error', (err) => {
        fs.unlink(dest);
        return cb(err.message);
    });
    file.on('error', (err) => { // Handle errors
        fs.unlink(dest); // Delete the file async. (But we don't check the result)
        return cb(err.message);
    });
};
gfxmonk 的回答在回调和file.close()完成之间有一个非常紧张的数据竞争。  file.close()实际上需要一个在关闭完成时调用的回调。否则,文件的立即使用可能会失败(很少见!)。
一个完整的解决方案是:
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
  var file = fs.createWriteStream(dest);
  var request = http.get(url, function(response) {
    response.pipe(file);
    file.on('finish', function() {
      file.close(cb);  // close() is async, call cb after close completes.
    });
  });
}
在不等待完成事件的情况下,幼稚的脚本可能会以不完整的文件结束。如果不cb通过 close安排回调,您可能会在访问文件和文件实际准备好之间发生竞争。