it-swarm.com.de

Wie kann ich eine Datei mit Node.js herunterladen (ohne Bibliotheken von Drittanbietern)?

Wie lade ich eine Datei mit Node.js herunter, ohne Bibliotheken von Drittanbietern zu verwenden?

Ich brauche nichts Besonderes. Ich möchte nur eine Datei von einer bestimmten URL herunterladen und sie dann in einem bestimmten Verzeichnis speichern.

323
greepow

Sie können eine HTTP GET-Anforderung erstellen und ihre response in einen beschreibbaren Dateistream pipe:

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);
});

Wenn Sie das Sammeln von Informationen in der Befehlszeile unterstützen möchten, z. B. Angabe einer Zieldatei oder eines Verzeichnisses oder einer URL, überprüfen Sie etwas wie Commander .

438
Michelle Tilley

Vergessen Sie nicht, Fehler zu behandeln! Der folgende Code basiert auf der Antwort von 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);
  });
};
446
Vince Yuan

Wie Brandon Tilley sagte, aber mit der entsprechenden Kontrolle:

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);
    });
  });
}

Ohne auf das finish-Ereignis zu warten, erhalten naive Skripts möglicherweise eine unvollständige Datei.

Edit: Danke an @Augusto Roman für den Hinweis, dass cb an file.close übergeben werden soll, nicht explizit aufgerufen wird.

121
gfxmonk

Apropos Umgang mit Fehlern, es ist noch besser, Fehler zu hören. Ich würde es sogar überprüfen, indem ich den Antwortcode überprüfe. Hier gilt der Erfolg nur für 200 Antwortcodes, andere Codes sind jedoch möglicherweise gut. 

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);
    });
};

Trotz der relativen Einfachheit dieses Codes würde ich empfehlen, das Modul request zu verwenden , da es viele weitere Protokolle verarbeitet (Hallo HTTPS!), Die von http nicht nativ unterstützt werden.

Das wäre so gemacht:

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);
    });
};
54
Buzut

die Antwort von gfxmonk hat einen sehr engen Datenwettlauf zwischen dem Rückruf und dem Abschluss der file.close(). file.close() nimmt tatsächlich einen Rückruf an, der aufgerufen wird, wenn das Schließen abgeschlossen ist. Andernfalls kann die sofortige Verwendung der Datei fehlschlagen (sehr selten!).

Eine Komplettlösung ist:

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.
    });
  });
}

Ohne auf das Beendigungsereignis zu warten, erhalten naive Skripte möglicherweise eine unvollständige Datei. Ohne den cb-Callback über close zu terminieren, kann es vorkommen, dass zwischen dem Zugriff auf die Datei und der tatsächlich bereitstehenden Datei ein Wettlauf stattfindet.

39
Augusto Roman

Vielleicht hat node.js sich geändert, aber es scheint, dass es Probleme mit den anderen Lösungen gibt (mit dem Knoten v8.1.2):

  1. Sie müssen file.close() nicht im Ereignis finish aufrufen. Standardmäßig ist fs.createWriteStream auf autoClose gesetzt: https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options
  2. file.close() sollte bei einem Fehler aufgerufen werden. Möglicherweise ist dies nicht erforderlich, wenn die Datei gelöscht wird (unlink()), normalerweise jedoch: https://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
  3. Temp-Datei wird auf statusCode !== 200 nicht gelöscht
  4. fs.unlink() ohne Rückruf ist veraltet (gibt Warnung aus)
  5. Wenn dest Datei vorhanden ist; es wird außer Kraft gesetzt

Nachfolgend finden Sie eine modifizierte Lösung (mit ES6 und Versprechungen), die diese Probleme löst.

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);
            }
        });
    });
}
13
Bjarke Pjedsted

für diejenigen, die auf der Suche nach einem auf Es6 basierenden Versprechen waren, denke ich, wäre dies etwa so: 

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));
13
mido

Lösung mit Timeout, Speicherverlust vermeiden:

Der folgende Code basiert auf der Antwort von 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();
    });
});

Erstellen Sie keine Datei, wenn Sie eine Fehlermeldung erhalten, und ziehen Sie es vor, nach x Sekunden die Anforderung mit timeout zu schließen.

13
A-312
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));
4
kayz1

Vince Yuans Code ist großartig, scheint aber etwas falsch zu sein.

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);
        });
    });
}
4
weed

Sie können https://github.com/douzi8/ajax-request#download verwenden.

request.download('http://res.m.ctrip.com/html5/Content/images/57.png', 
  function(err, res, body) {}
);
3
douzi

Wenn Sie Express verwenden, verwenden Sie die Methode res.download (). ansonsten fs modul verwenden.

app.get('/read-Android', function(req, res) {
   var file = "/home/sony/Documents/docs/Android.apk";
    res.download(file) 
}); 

(oder)

   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");
          }
        });  
    }
2
KARTHIKEYAN.A

Pfad: img Typ: jpg Zufällige 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;
}
1
databilim

Download mit Versprechen, das einen lesbaren Stream auflöst. Legen Sie zusätzliche Logik für die Weiterleitung bereit.

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);
    }
});
1
wdanxna

Hallo, ich denke, Sie können das child_process -Modul und den curl-Befehl verwenden.

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()

Außerdem können Sie, wenn Sie große, mehrere Dateien herunterladen möchten, das Modul cluster verwenden, um weitere CPU-Kerne zu verwenden.

0
wenningzhang
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);
  });
};
0
Alex Pilugin

Sie können versuchen, res.redirect für die Download-URL der https-Datei zu verwenden. Anschließend wird die Datei heruntergeladen.

Wie: res.redirect('https//static.file.com/file.txt');

0
Yin

Ohne Bibliothek könnte es fehlerhaft sein, nur um darauf hinzuweisen. Hier sind ein paar:

Hier mein Vorschlag:

  • System-Tool wie wget oder curl aufrufen
  • verwenden Sie ein Tool wie node-wget-promise , das auch sehr einfach zu verwenden ist. var wget = require('node-wget-promise'); wget('http://nodejs.org/images/logo.svg');
0
Geng Jiawen
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');
});
0
Pankaj