web-dev-qa-db-fra.com

nodejs plusieurs requêtes http en boucle

J'essaie de créer un lecteur de flux simple dans node et je suis confronté à un problème de requêtes multiples dans node.js . Par exemple, j'ai un tableau avec des URL de type:

urls = [
"http://url1.com/rss.xml",
"http://url2.com",
"http://url3.com"];

Maintenant, je veux obtenir le contenu de chaque URL. La première idée était d'utiliser for(var i in urls) mais ce n'est pas une bonne idée. la meilleure option serait de le faire de manière asynchrone mais je ne sais pas comment le faire.

Des idées?

MODIFIER:

J'ai ce code:

var data = [];
for(var i = 0; i<urls.length; i++){
    http.get(urls[i], function(response){
    console.log('Reponse: ', response.statusCode, ' from url: ', urls[i]);
    var body = '';
    response.on('data', function(chunk){
        body += chunk;
    });

    response.on('end', function() {
        data.Push(body);
    });
}).on('error', function(e){
    console.log('Error: ', e.message);
});
}

Le problème est que le premier est la ligne d’appel "http.get ..." pour chaque élément en boucle et, après cet événement, on appelle response.on ('data') et ensuite cet appel.on ('end'). Cela fait des dégâts et je ne sais pas comment gérer ça.

27
SzymonPoltorak

Par défaut, les demandes de noeud http sont asynchrones. Vous pouvez les démarrer séquentiellement dans votre code et appeler une fonction qui démarrera lorsque toutes les demandes seront effectuées. Vous pouvez le faire à la main (compter la demande finie/commencée) ou utiliser async.js

C'est la méthode sans dépendance (vérification d'erreur omise):

var http = require('http');    
var urls = ["http://www.google.com", "http://www.example.com"];
var responses = [];
var completed_requests = 0;

for (i in urls) {
    http.get(urls[i], function(res) {
        responses.Push(res);
        completed_requests++;
        if (completed_requests == urls.length) {
            // All download done, process responses array
            console.log(responses);
        }
    });
}
32
toasted_flakes

Je sais que cette question est ancienne, mais je pense qu'une meilleure solution serait d'utiliser JavaScripts Promise.all():

const request = require('request-promise');
const urls = ["http://www.google.com", "http://www.example.com"];
const promises = urls.map(url => request(url));
Promise.all(promises).then((data) => {
    // data = [promise1,promise2]
});
26
werne2j

Vous devez vérifier que le end (événement de fin de données) a été appelé le nombre exact de demandes ... Voici un exemple de travail:

var http = require('http');
var urls = ['http://adrianmejia.com/atom.xml', 'http://twitrss.me/Twitter_user_to_rss/?user=amejiarosario'];
var completed_requests = 0;

urls.forEach(function(url) {
  var responses = [];
  http.get(url, function(res) {
    res.on('data', function(chunk){
      responses.Push(chunk);
    });

    res.on('end', function(){
      if (completed_requests++ == urls.length - 1) {
        // All downloads are completed
        console.log('body:', responses.join());
      }      
    });
  });
})
23
Adrian

Vous pouvez utiliser n'importe quelle bibliothèque de promesses avec une implémentation ".all". J'utilise la bibliothèque RSVP, c'est assez simple.

var downloadFileList = [url:'http://stuff',dataname:'filename to download']
var ddownload = downloadFileList.map(function(id){
          var dataname = id.dataname;
          var url = id.url;
          return new RSVP.Promise(function(fulfill, reject) {
           var stream = fs.createWriteStream(dataname);
            stream.on('close', function() {
            console.log(dataname+' downloaded');
            fulfill();  
            });
          request(url).on('error', function(err) {
    console.log(err);
    reject();
  }).pipe(stream);
        });
        });      
        return new RSVP.hashSettled(ddownload);
0