Laisser un commentaire

Télécharger des fichiers depuis le web en Node.js

Quelle que soit l’application sur laquelle on travaille, il arrive forcement un moment ou cette dernière doit automatiquement télécharger des ressources web. Des images de profil téléchargées depuis Gravatar ou Twitter par exemple. Voyons comment créer rapidement une fonction de téléchargement.

Il existe un module fort pratique pour nous aider dans notre tâche, j’ai nommé request,
un client http. Néanmoins, nous ajouterons aussi une manière native, qui ne dépende d’aucun module externe à node.

Télécharger un fichier avec request

Commençons par la première méthode, avec le module request, car elle est plus souple. On commence bien entendu par installer request dans le projet avec npm install --save request. C’est parti !

Dans le mesure où on est en nodejs et pas dans un navigateur, j’utilise ici directement du code en ES6. Le code est suffisamment commenté pour que vous puissiez comprendre.

// on récupère les modules nécessaires
const fs = require('fs');
const request = require('request');

function download(url, dest, cb) {
    // on créé un stream d'écriture qui nous permettra
    // d'écrire au fur et à mesure que les données sont téléchargées
    const file = fs.createWriteStream(dest);

    // on lance le téléchargement
    const sendReq = request.get(url);

    // on vérifie la validité du code de réponse HTTP
    sendReq.on('response', (response) => {
        if (response.statusCode !== 200) {
            return cb('Response status was ' + response.statusCode);
        }
    });

    // au cas où request rencontre une erreur
    // on efface le fichier partiellement écrit
    // puis on passe l'erreur au callback
    sendReq.on('error', (err) => {
        fs.unlink(dest);
        cb(err.message);
    });

    // écrit directement le fichier téléchargé
    sendReq.pipe(file);

    // lorsque le téléchargement est terminé
    // on appelle le callback
    file.on('finish', () => {
        // close étant asynchrone,
        // le cb est appelé lorsque close a terminé
        file.close(cb);
    });

    // si on rencontre une erreur lors de l'écriture du fichier
    // on efface le fichier puis on passe l'erreur au callback
    file.on('error', (err) => {
        // on efface le fichier sans attendre son effacement
        // on ne vérifie pas non plus les erreur pour l'effacement
        fs.unlink(dest);
        cb(err.message);
    });
};

Simple et efficace n’est-ce pas ? Vous passez donc à cette fonction une url, un fichier de destination et un callback afin de savoir quand c’est terminé et s’il y a eu des erreurs. Voici comment l’utiliser :

download('https://buzut.fr/wp-content/themes/buzut-theme/img/logo.jpg', '/var/www/files/buzut-logo.jpg', (err) => {
    if (err) {
        console.error(err);
        return;
    }

    console.log('Téléchargement terminé !');
})

Télécharger un fichier sans aucune dépendance

Le code reste ici assez similaire. On va utiliser le module http ou https au lieu d’utiliser request.

// on récupère les modules nécessaires
var fs = require('fs');
var http = require('http');
var https = require('https');

function download(url, dest, cb) {
    // on créé un stream d'écriture qui nous permettra
    // d'écrire au fur et à mesure que les données sont téléchargées
    const file = fs.createWriteStream(dest);
    let httpMethod;

    // afin d'utiliser le bon module on vérifie si notre url
    // utilise http ou https
    if (url.indexOf(('https://')) !== -1) httpMethod = https;
    else httpMethod = http;

    // on lance le téléchargement
    const request = httpMethod.get(url, (response) => {
        // on vérifie la validité du code de réponse HTTP
        if (response.statusCode !== 200) {
            return cb('Response status was ' + response.statusCode);
        }

        // écrit directement le fichier téléchargé
        response.pipe(file);

        // lorsque le téléchargement est terminé
        // on appelle le callback
        file.on('finish', () => {
            // close étant asynchrone,
            // le cb est appelé lorsque close a terminé
            file.close(cb);
        });
    });

    // check for request error too
    request.on('error', (err) => {
        fs.unlink(dest);
        cb(err.message);
    });

    // si on rencontre une erreur lors de l'écriture du fichier
    // on efface le fichier puis on passe l'erreur au callback
    file.on('error', (err) => {
        // on efface le fichier sans attendre son effacement
        // on ne vérifie pas non plus les erreur pour l'effacement
        fs.unlink(dest);
        cb(err.message);
    });
}

Et voilà pour la méthode native. Elle s’utilise exactement de la même manière que l’autre fonction.

Vous noterez que dans notre cas, il n’y a pas une grande différence entre les deux fonctions. Le module request trouve tout son intérêt dès lors qu’il nous faut nous identifier ou supporter d’autres méthodes http que les simples GET ou POST.

Au rang des améliorations, il peut aussi être utile de vérifier d’autres statuts HTTP. Je considère ici que toute réponse autre que 200 est une erreur, ce qui n’est pas forcément le cas.

Vous noterez que je manquais d’exemples d’usage dans mon intro… Qu’est-ce que vous téléchargez dans vos applications ?

Commentaires

Rejoignez la discussion !

Vous pouvez utiliser Markdown pour les liens [ancre de lien](url), la mise en *italique* et en **gras**. Enfin pour le code, vous pouvez utiliser la syntaxe `inline` et la syntaxe bloc

```
ceci est un bloc
de code
```