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 souhaite uniquement télécharger un fichier à partir d'une URL donnée, puis l'enregistrer dans un répertoire donné.
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 souhaite uniquement télécharger un fichier à partir d'une URL donnée, puis l'enregistrer dans un répertoire donné.
Réponses:
Vous pouvez créer une GET
demande HTTP et la diriger response
vers 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 - comme spécifier un fichier ou un répertoire cible, ou une URL - consultez quelque chose comme Commander .
node.js:201 throw e; // process.nextTick error, or 'error' event on first tick ^ Error: connect ECONNREFUSED at errnoException (net.js:646:11) at Object.afterConnect [as oncomplete] (net.js:637:18)
.
http.get
ligne; peut-être http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg
(et remplacer file.png
par file.jpg
).
https
vous devez utiliser https
sinon il générera une erreur.
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);
});
};
download()
lui - même pipe
capable?
Comme l'a dit Michelle 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);
http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb);
});
});
}
Sans attendre l' finish
événement, les scripts naïfs peuvent se retrouver avec un fichier incomplet.
Edit: Merci à @Augusto Roman d'avoir souligné qui cb
devrait être transmis à file.close
, pas appelé explicitement.
download()
, comment ferais-je? Que placerais-je comme cb
argument? J'ai le download('someURI', '/some/destination', cb)
mais je ne comprends pas quoi mettre dans le cb
En parlant de gestion des erreurs, il vaut mieux écouter aussi les erreurs de demande. Je validerais même en vérifiant le code de réponse. Ici, il est considéré comme un succès uniquement pour 200 codes de réponse, mais d'autres codes peuvent être bons.
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 de requête car il gère beaucoup plus de protocoles (bonjour HTTPS!) Qui ne sont pas supportés nativement par http
.
Cela se ferait ainsi:
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);
});
};
response.statusCode !== 200
le cb on finish
ne sera jamais appelé.
La réponse de gfxmonk a une course de données très serrée entre le rappel et la file.close()
fin. file.close()
prend en fait un rappel qui est appelé lorsque la fermeture est terminée. Sinon, les utilisations immédiates du fichier peuvent échouer (très rarement!).
Une solution complète 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 cb
rappel via la fermeture, vous pouvez obtenir une course entre l'accès au fichier et le fichier réellement prêt.
var request =
est supprimée?
Peut-être que node.js a changé, mais il semble qu'il y ait des problèmes avec les autres solutions (en utilisant le nœud v8.1.2):
file.close()
lors de l' finish
événement. Par défaut, le fs.createWriteStream
est défini sur autoClose: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_optionsfile.close()
doit être appelé en cas d'erreur. Peut-être que ce n'est pas nécessaire lorsque le fichier est supprimé ( unlink()
), mais normalement c'est: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_optionsstatusCode !== 200
fs.unlink()
sans rappel est obsolète (affiche un avertissement)dest
fichier existe; il est annuléVous trouverez ci-dessous une solution modifiée (utilisant ES6 et promesses) qui gère 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);
}
});
});
}
const https = require("https");
parconst http = require("http");
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 obtenez une erreur et préférez utiliser le délai d'expiration pour fermer votre demande après X secondes.
http.get("http://example.com/yourfile.html",function(){})
http.get
. La fuite de mémoire ne se produit que si le fichier prend trop de temps pour être téléchargé.
pour ceux qui sont venus à la recherche de promesses basées sur le 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));
responseSet
flag a causé, pour une raison que je n'avais pas eu le temps d'examiner, mon fichier à télécharger de manière incomplète. Aucune erreur n'est apparue mais le fichier .txt que je remplissais avait la moitié des lignes qui devaient être là. La suppression de la logique du drapeau l'a corrigé. Je voulais juste signaler si quelqu'un avait des problèmes avec l'approche. Toujours, +1
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);
});
});
}
Je préfère request () car vous pouvez utiliser à la fois http et https.
request('http://i3.ytimg.com/vi/J---aiyznGQ/mqdefault.jpg')
.pipe(fs.createWriteStream('cat.jpg'))
"As of Feb 11th 2020, request is fully deprecated. No new changes are expected to land. In fact, none have landed for some time."
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));
Salut , Je pense que vous pouvez utiliser le module child_process et la commande curl.
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 le module de cluster pour utiliser plus de cœurs de processeur.
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) {}
);
ajax-request
n'est pas une bibliothèque tierce?
Téléchargez à l'aide de promise, qui résout un flux lisible. mettre une 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);
}
});
Si vous utilisez la méthode express use res.download (). sinon utilisation du 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");
}
});
}
OPar conséquent, si vous utilisez un pipeline , il fermera tous les autres flux et s'assurera qu'il n'y a pas de fuite de mémoire.
Exemple de travail:
const http = require('http'); const { pipeline } = require('stream'); const fs = require('fs'); const file = fs.createWriteStream('./file.jpg'); http.get('http://via.placeholder.com/150/92c952', response => { pipeline( response, file, err => { if (err) console.error('Pipeline failed.', err); else console.log('Pipeline succeeded.'); } ); });
De ma réponse à "Quelle est la différence entre .pipe et .pipeline sur les flux" .
Chemin: type img: jpg uniqid aléatoire
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;
}
Sans bibliothèque, il pourrait être bogué pour le signaler. Voici quelques-uns:
Protocol "https:" not supported.
Voici ma suggestion:
wget
oucurl
var wget = require('node-wget-promise');
wget('http://nodejs.org/images/logo.svg');
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);
});
};
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');
});
Voici encore une autre façon de le gérer sans dépendance tierce et de rechercher également des redirections:
var download = function(url, dest, cb) {
var file = fs.createWriteStream(dest);
https.get(url, function(response) {
if ([301,302].indexOf(response.statusCode) !== -1) {
body = [];
download(response.headers.location, dest, cb);
}
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
});
}
download.js (ie /project/utils/download.js)
const fs = require('fs');
const request = require('request');
const download = (uri, filename, callback) => {
request.head(uri, (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);
});
};
module.exports = { download };
app.js
...
// part of imports
const { download } = require('./utils/download');
...
// add this function wherever
download('https://imageurl.com', 'imagename.jpg', () => {
console.log('done')
});
Nous pouvons utiliser le module de nœud de téléchargement et son très simple, veuillez vous référer ci-dessous https://www.npmjs.com/package/download
var requestModule=require("request");
requestModule(filePath).pipe(fs.createWriteStream('abc.zip'));