Comment télécharger un fichier avec Node.js sans utiliser de bibliothèques tierces ?
Je n'ai besoin de rien de spécial. Je veux seulement télécharger un fichier à partir d'une URL donnée, puis l'enregistrer dans un répertoire donné.
Vous pouvez créer une demande HTTP GET
et diriger sa response
dans un flux de fichiers accessible en écriture:
const http = require('http');
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);
});
Si vous souhaitez prendre en charge la collecte d'informations sur la ligne de commande, telle que la spécification d'un fichier ou d'un répertoire cible, ou d'une URL, recherchez un élément tel que Commander .
N'oubliez pas de gérer les erreurs! Le code suivant est basé sur la réponse d'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);
});
};
Comme l'a dit Brandon Tilley, mais avec le flux de contrôle approprié:
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);
});
});
}
Sans attendre l'événement finish
, les scripts naïfs peuvent se retrouver avec un fichier incomplet.
Edit: Merci à @Augusto Roman d'avoir signalé que cb
doit être passé à file.close
, non appelé explicitement.
En parlant d’erreurs de gestion, il est encore plus intéressant d’écouter les erreurs de requête. Je validerais même en vérifiant le code de réponse. Ici, le succès n’est considéré que pour 200 codes de réponse, mais d’autres codes pourraient être utiles.
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);
});
};
Malgré la relative simplicité de ce code, je conseillerais d'utiliser le module request car il gère beaucoup plus de protocoles (hello HTTPS!) Qui ne sont pas supportés nativement par http
.
Cela se ferait comme suit:
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);
});
};
la réponse de gfxmonk a une course de données très serrée entre le rappel et le file.close()
complétant. file.close()
prend en réalité un rappel qui est appelé lorsque la fermeture est terminée. Sinon, les utilisations immédiates du fichier risquent d’échouer (très rarement!).
Une solution complète c'est:
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.
});
});
}
Sans attendre l'événement de fin, les scripts naïfs peuvent se retrouver avec un fichier incomplet. Sans planifier le rappel cb
via close, vous risquez de perdre du temps entre l'accès au fichier et le fait que le fichier est prêt.
Node.js a peut-être changé, mais il semble y avoir quelques problèmes avec les autres solutions (en utilisant node v8.1.2):
file.close()
dans l'événement finish
. Par défaut, fs.createWriteStream
est défini sur autoClose: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_optionsfile.close()
devrait être appelé en cas d'erreur. Cela n’est peut-être pas nécessaire lorsque le fichier est supprimé (unlink()
), mais normalement il s’agit: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_optionsstatusCode !== 200
fs.unlink()
sans rappel est obsolète (avertissement de sortie)dest
existe; il est écraséVous trouverez ci-dessous une solution modifiée (à l’aide de ES6 et de promesses) qui résout ces problèmes.
const http = require("http");
const fs = require("fs");
function download(url, dest) {
return new Promise((resolve, reject) => {
const file = fs.createWriteStream(dest, { flags: "wx" });
const request = http.get(url, response => {
if (response.statusCode === 200) {
response.pipe(file);
} else {
file.close();
fs.unlink(dest, () => {}); // Delete temp file
reject(`Server responded with ${response.statusCode}: ${response.statusMessage}`);
}
});
request.on("error", err => {
file.close();
fs.unlink(dest, () => {}); // Delete temp file
reject(err.message);
});
file.on("finish", () => {
resolve();
});
file.on("error", err => {
file.close();
if (err.code === "EEXIST") {
reject("File already exists");
} else {
fs.unlink(dest, () => {}); // Delete temp file
reject(err.message);
}
});
});
}
pour ceux qui sont venus à la recherche d'une manière basée sur la promesse de style es6, je suppose que ce serait quelque chose comme:
var http = require('http');
var fs = require('fs');
function pDownload(url, dest){
var file = fs.createWriteStream(dest);
return new Promise((resolve, reject) => {
var responseSent = false; // flag to make sure that response is sent only once.
http.get(url, response => {
response.pipe(file);
file.on('finish', () =>{
file.close(() => {
if(responseSent) return;
responseSent = true;
resolve();
});
});
}).on('error', err => {
if(responseSent) return;
responseSent = true;
reject(err);
});
});
}
//example
pDownload(url, fileLocation)
.then( ()=> console.log('downloaded file no issues...'))
.catch( e => console.error('error while downloading', e));
Le code suivant est basé sur la réponse de Brandon Tilley:
var http = require('http'),
fs = require('fs');
var request = http.get("http://example12345.com/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();
});
});
Ne créez pas de fichier lorsque vous recevez une erreur et préférez utiliser timeout pour fermer votre demande après X secondes.
const download = (url, path) => new Promise((resolve, reject) => {
http.get(url, response => {
const statusCode = response.statusCode;
if (statusCode !== 200) {
return reject('Download error!');
}
const writeStream = fs.createWriteStream(path);
response.pipe(writeStream);
writeStream.on('error', () => reject('Error writing to file!'));
writeStream.on('finish', () => writeStream.close(resolve));
});}).catch(err => console.error(err));
Le code de Vince Yuan est génial, mais il semble que quelque chose ne va pas.
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);
});
});
}
Vous pouvez utiliser https://github.com/douzi8/ajax-request#download
request.download('http://res.m.ctrip.com/html5/Content/images/57.png',
function(err, res, body) {}
);
Si vous utilisez exprès, utilisez la méthode res.download (). sinon, utiliser le module fs.
app.get('/read-Android', function(req, res) {
var file = "/home/sony/Documents/docs/Android.apk";
res.download(file)
});
(ou)
function readApp(req,res) {
var file = req.fileName,
filePath = "/home/sony/Documents/docs/";
fs.exists(filePath, function(exists){
if (exists) {
res.writeHead(200, {
"Content-Type": "application/octet-stream",
"Content-Disposition" : "attachment; filename=" + file});
fs.createReadStream(filePath + file).pipe(res);
} else {
res.writeHead(400, {"Content-Type": "text/plain"});
res.end("ERROR File does NOT Exists.ipa");
}
});
}
Chemin: img Type: jpg Aléatoire uniqid
function resim(url) {
var http = require("http");
var fs = require("fs");
var sayi = Math.floor(Math.random()*10000000000);
var uzanti = ".jpg";
var file = fs.createWriteStream("img/"+sayi+uzanti);
var request = http.get(url, function(response) {
response.pipe(file);
});
return sayi+uzanti;
}
Téléchargez en utilisant promesse, qui résolvent un flux lisible. mettre de la logique supplémentaire pour gérer la redirection.
var http = require('http');
var promise = require('bluebird');
var url = require('url');
var fs = require('fs');
var assert = require('assert');
function download(option) {
assert(option);
if (typeof option == 'string') {
option = url.parse(option);
}
return new promise(function(resolve, reject) {
var req = http.request(option, function(res) {
if (res.statusCode == 200) {
resolve(res);
} else {
if (res.statusCode === 301 && res.headers.location) {
resolve(download(res.headers.location));
} else {
reject(res.statusCode);
}
}
})
.on('error', function(e) {
reject(e);
})
.end();
});
}
download('http://localhost:8080/redirect')
.then(function(stream) {
try {
var writeStream = fs.createWriteStream('holyhigh.jpg');
stream.pipe(writeStream);
} catch(e) {
console.error(e);
}
});
Bonjour , Je pense que vous pouvez utiliser child_process module and curl command.
const cp = require('child_process');
let download = async function(uri, filename){
let command = `curl -o ${filename} '${uri}'`;
let result = cp.execSync(command);
};
async function test() {
await download('http://zhangwenning.top/20181221001417.png', './20181221001417.png')
}
test()
De plus, lorsque vous souhaitez télécharger de gros fichiers multiples, vous pouvez utiliser cluster module pour utiliser davantage de cœurs de processeur.
function download(url, dest, cb) {
var request = http.get(url, function (response) {
const settings = {
flags: 'w',
encoding: 'utf8',
fd: null,
mode: 0o666,
autoClose: true
};
// response.pipe(fs.createWriteStream(dest, settings));
var file = fs.createWriteStream(dest, settings);
response.pipe(file);
file.on('finish', function () {
let okMsg = {
text: `File downloaded successfully`
}
cb(okMsg);
file.end();
});
}).on('error', function (err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
let errorMsg = {
text: `Error in file downloadin: ${err.message}`
}
if (cb) cb(errorMsg);
});
};
Vous pouvez essayer d'utiliser res.redirect
dans l'URL de téléchargement du fichier https, puis le fichier sera téléchargé.
Comme: res.redirect('https//static.file.com/file.txt');
Sans bibliothèque, il pourrait être difficile de signaler. Voici quelques-uns:
Protocol "https:" not supported.
Voici ma suggestion:
wget
ou curl
var wget = require('node-wget-promise'); wget('http://nodejs.org/images/logo.svg');
var fs = require('fs'),
request = require('request');
var download = function(uri, filename, callback){
request.head(uri, function(err, res, body){
console.log('content-type:', res.headers['content-type']);
console.log('content-length:', res.headers['content-length']);
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
download('https://www.cryptocompare.com/media/19684/doge.png', 'icons/taskks12.png', function(){
console.log('done');
});