How do I download a file with Node.js without using third-party libraries?
I don't need anything special. I only want to download a file from a given URL, and then save it to a given directory.
You can create an HTTP GET
request and pipe its response
into a writable file stream:
var http = require('http');
var fs = require('fs');
var file = fs.createWriteStream("file.jpg");
var request = http.get("http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg", function(response) {
response.pipe(file);
});
If you want to support gathering information on the command line--like specifying a target file or directory, or URL--check out something like Commander.
As Brandon Tilley said, but with the appropriate control flow:
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);
});
});
}
Without waiting for the finish
event, naive scripts may end up with an incomplete file.
Edit: Thanks to @Augusto Roman for pointing out that cb
should be passed to file.close
, not called explicitly.
Don't forget to handle errors! The following code is based on Augusto Roman's answer.
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);
});
};
gfxmonk's answer has a very tight data race between the callback and the file.close() completing. file.close() actually takes a callback that is called when the close has completed. Otherwise, immediate uses of the of the file may fail (very rarely!).
A complete solution is:
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.
});
});
}
Without waiting for the finish event, naive scripts may end up with an incomplete file. Without scheduling the cb callback via close, you may get a race between accessing the file and the file actually being ready.
You can use https://github.com/douzi8/ajax-request#download
request.download('http://res.m.ctrip.com/html5/Content/images/57.png',
function(err, res, body) {}
);
The following code is based on Brandon Tilley's answer :
var http = require('http'),
fs = require('fs');
var request = http.get("yourfile.html", function(response) {
if (response.statusCode === 200) {
var file = fs.createWriteStream("copy.html");
response.pipe(file);
}
// Add timeout.
request.setTimeout(12000, function () {
request.abort();
});
});
Don't make file when you get an error, and prefere to use timeout to close your request after X secondes.
Vince Yuan's code is great but it seems to be something wrong.
function download(url, dest, callback) {
var file = fs.createWriteStream(dest);
var request = http.get(url, function (response) {
response.pipe(file);
file.on('finish', function () {
file.close(callback); // close() is async, call callback after close completes.
});
file.on('error', function (err) {
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (callback)
callback(err.message);
});
});
}
If nothing else works, try using wget:
var exec = require('child_process').exec;
var downloadFileWGET = function(url, dest) {
var wget = 'wget ' + url + ' -O ' + dest;
// excute wget using child_process exec function
var child = exec(wget, function(err, stdout, stderr) {
if (err) throw err;
else console.log(dest + ' downloaded to ' + dest);
});
};