如何在不使用第三方库的情况下使用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安排回调,您可能会在访问文件和文件实际准备好之间发生竞争。