webentwicklung-frage-antwort-db.com.de

Herunterladen von Bildern mit node.js

Ich versuche, ein Skript zum Herunterladen von Bildern mit node.js zu schreiben. Das habe ich bisher:

var maxLength = 10 // 10mb
var download = function(uri, callback) {
  http.request(uri)
    .on('response', function(res) {
      if (res.headers['content-length'] > maxLength*1024*1024) {
        callback(new Error('Image too large.'))
      } else if (!~[200, 304].indexOf(res.statusCode)) {
        callback(new Error('Received an invalid status code.'))
      } else if (!res.headers['content-type'].match(/image/)) {
        callback(new Error('Not an image.'))
      } else {
        var body = ''
        res.setEncoding('binary')
        res
          .on('error', function(err) {
            callback(err)
          })
          .on('data', function(chunk) {
            body += chunk
          })
          .on('end', function() {
            // What about Windows?!
            var path = '/tmp/' + Math.random().toString().split('.').pop()
            fs.writeFile(path, body, 'binary', function(err) {
              callback(err, path)
            })
          })
      }
    })
    .on('error', function(err) {
      callback(err)
    })
    .end();
}

Ich möchte dies jedoch robuster machen:

  1. Gibt es Bibliotheken, die dies tun und es besser machen?
  2. Gibt es eine Chance, dass Antwortheader lügen (über die Länge, über den Inhaltstyp)?
  3. Gibt es andere Statuscodes, die mir wichtig sind? Soll ich mich mit Weiterleitungen beschäftigen?
  4. Ich glaube, ich habe irgendwo gelesen, dass die Kodierung von binary veraltet sein wird. Was mache ich dann
  5. Wie kann ich das unter Windows zum Laufen bringen?
  6. Können Sie dieses Skript auf andere Weise verbessern?

Warum: Für eine ähnliche Funktion wie imgur, bei der Benutzer mir eine URL geben können, lade ich das Bild herunter und stelle das Bild in mehreren Größen wieder her.

141
Jonathan Ong

Ich würde vorschlagen, das Anforderungsmodul zu verwenden. Das Herunterladen einer Datei ist so einfach wie der folgende Code:

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.google.com/images/srpr/logo3w.png', 'google.png', function(){
  console.log('done');
});
348

Ich bin vor einigen Tagen auf dieses Problem gestoßen. Für eine reine NodeJS-Antwort würde ich vorschlagen, Stream zu verwenden, um die Blöcke zusammenzuführen.

var http = require('http'),                                                
    Stream = require('stream').Transform,                                  
    fs = require('fs');                                                    

var url = 'http://www.google.com/images/srpr/logo11w.png';                    

http.request(url, function(response) {                                        
  var data = new Stream();                                                    

  response.on('data', function(chunk) {                                       
    data.Push(chunk);                                                         
  });                                                                         

  response.on('end', function() {                                             
    fs.writeFileSync('image.png', data.read());                               
  });                                                                         
}).end();

Die neuesten Versionen von Node funktionieren nicht gut mit binären Strings, daher ist das Zusammenführen von Chunks mit Strings keine gute Idee, wenn Sie mit binären Daten arbeiten.

* Seien Sie vorsichtig, wenn Sie 'data.read ()' verwenden, da dies den Stream für den nächsten 'read ()' - Vorgang leeren wird. Wenn Sie es mehrmals verwenden möchten, bewahren Sie es an einem Ort auf.

22
Nihey Takizawa

Sie können Axios (einen Versprechen - basierten HTTP-Client für Node.js) zum Herunterladen verwenden Bilder in der Reihenfolge Ihrer Wahl in einer asynchronen Umgebung :

npm i axios

Anschließend können Sie das folgende grundlegende Beispiel verwenden, um mit dem Herunterladen von Bildern zu beginnen:

const fs = require('fs');
const axios = require('axios');

/* ============================================================
  Function: Download Image
============================================================ */

const download_image = (url, image_path) =>
  axios({
    url,
    responseType: 'stream',
  }).then(
    response =>
      new Promise((resolve, reject) => {
        response.data
          .pipe(fs.createWriteStream(image_path))
          .on('finish', () => resolve())
          .on('error', e => reject(e));
      }),
  );

/* ============================================================
  Download Images in Order
============================================================ */

(async () => {
  let example_image_1 = await download_image('https://example.com/test-1.png', 'example-1.png');

  console.log(example_image_1.status); // true
  console.log(example_image_1.error); // ''

  let example_image_2 = await download_image('https://example.com/does-not-exist.png', 'example-2.png');

  console.log(example_image_2.status); // false
  console.log(example_image_2.error); // 'Error: Request failed with status code 404'

  let example_image_3 = await download_image('https://example.com/test-3.png', 'example-3.png');

  console.log(example_image_3.status); // true
  console.log(example_image_3.error); // ''
})();
10
Grant Miller

wenn Sie den Fortschritt herunterladen möchten, versuchen Sie Folgendes:

var fs = require('fs');
var request = require('request');
var progress = require('request-progress');

module.exports = function (uri, path, onProgress, onResponse, onError, onEnd) {
    progress(request(uri))
    .on('progress', onProgress)
    .on('response', onResponse)
    .on('error', onError)
    .on('end', onEnd)
    .pipe(fs.createWriteStream(path))
};

wie benutzt man:

  var download = require('../lib/download');
  download("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png", "~/download/logo.png", function (state) {
            console.log("progress", state);
        }, function (response) {
            console.log("status code", response.statusCode);
        }, function (error) {
            console.log("error", error);
        }, function () {
            console.log("done");
        });

hinweis: Sie sollten sowohl Anforderungs- als auch Anforderungsfortschrittsmodule installieren, indem Sie Folgendes verwenden:

npm install request request-progress --save
9

Darauf aufbauend habe ich diese Version verwendet, wenn jemand Fehler in den Schreib-/Lesestreams behandeln muss. Beachten Sie die Funktion stream.read() im Falle eines Schreibfehler, damit wir den Lesevorgang beenden und close für den Lesestream auslösen können.

var download = function(uri, filename, callback){
  request.head(uri, function(err, res, body){
    if (err) callback(err, filename);
    else {
        var stream = request(uri);
        stream.pipe(
            fs.createWriteStream(filename)
                .on('error', function(err){
                    callback(error, filename);
                    stream.read();
                })
            )
        .on('close', function() {
            callback(null, filename);
        });
    }
  });
};
4
VladFr
var fs = require('fs'),
http = require('http'),
https = require('https');

var Stream = require('stream').Transform;

var downloadImageToUrl = (url, filename, callback) => {

    var client = http;
    if (url.toString().indexOf("https") === 0){
      client = https;
     }

    client.request(url, function(response) {                                        
      var data = new Stream();                                                    

      response.on('data', function(chunk) {                                       
         data.Push(chunk);                                                         
      });                                                                         

      response.on('end', function() {                                             
         fs.writeFileSync(filename, data.read());                               
      });                                                                         
   }).end();
};

downloadImageToUrl('https://www.google.com/images/srpr/logo11w.png', 'public/uploads/users/abc.jpg');
4
Chandan Chhajer

Dies ist eine Erweiterung von Cezarys Antwort. Wenn Sie es in ein bestimmtes Verzeichnis herunterladen möchten, verwenden Sie dieses. Verwenden Sie statt var auch const. So ist es sicher.

const fs = require('fs');
const request = require('request');
var download = function(uri, filename, callback){
  request.head(uri, function(err, res, body){    
    request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
  });
};

download('https://www.google.com/images/srpr/logo3w.png', './images/google.png', function(){
  console.log('done');
});
3
Ahsan Ahmed