J’ai en tête un projet à réaliser avec NodeJs. Je vous en parlerer plus tard. Pour ce projet, j’ai besoin de pouvoir uploader des images. Je suis donc parti à la recherche de tutoriel pour voir cela. J’en ai trouvé plusieurs, mais beaucoup n’était pas adapté à ma version d’Express. Puis finalement, j’en ai trouvé un simple et efficace que vous pouvez voir à cette page. J’y ai ajouté une subtilité en m’inspirant pour le rendre un peu plus élégant à partir délément vu sur ce topic de stackoverflow. Ceci n’est pas vraiment un tutoriel, c’est plus un mémo que je rend publique afin qu’il puisse être éventuellement utile à d’autres...
Pour info, je suis sous Ubuntu.
Installer les modules nécessaires
Cette mini application de téléchargement de fichier se base principalement sur le module Formidable.
Pour l’installer en utilisant npm :
- npm install formidable@latest
Elle utilise aussi le module : fs-extra qui ajoute des méthodes pour gérer les fichiers qui ne sont pas présente dans le module natif de NodeJS fs.
Pour l’installer en utilisant npm :
- npm install fs-extra
Elle utilise aussi le module : [path>http://nodejs.org/api/path.html] qui gère les chemins. En fait, il génère des chaînes de caractères pour les chemins, mais ne vérifie pas si ceci sont valides...
Pour l’installer en utilisant npm :
- npm install path
Créer les dossiers nécessaires
Dans le dossier de la mini application, créer les dossier « temp » et « upload ». Soit à la main, soit en ligne de commande depuis votre dossier racine avec : mkdir upload
et mkdir temp
.
Coder la mini application d’upload
Je vais procéder étape par étape pour bien vois ce qui se passe.
Je vais commencer par créer un fichier app.js
à la racine de mon application avec un de mes éditeur préféré : Geany. Y mettre ce code :
- var formidable = require('formidable'),
- http = require('http'),
- util = require('util'),
- fs = require('fs-extra'),
- path = require("path");
- http.createServer(function(req, res) {
- /* Display the file upload form. */
- res.writeHead(200, {'content-type': 'text/html'});
- res.end(
- '<form action="/upload" enctype="multipart/form-data" method="post">'+
- '<input type="text" name="title"><br>'+
- '<input type="file" name="upload" multiple="multiple"><br>'+
- '<input type="submit" value="Upload">'+
- '</form>'
- );
- }).listen(8080);
Le but est d’afficher un formulaire sans plus d’artifice...
Dans le terminal, depuis la racine de la mini application, faire un node app.js
. Puis, se rendre sur : http://localhost:8080/. Un formulaire devrait apparaitre.
Maintenant, je vais ajouter un bout de code pour traiter ce qui est soumis via le formulaire :
- var formidable = require('formidable'),
- http = require('http'),
- util = require('util'),
- fs = require('fs-extra'),
- path = require("path");
- http.createServer(function(req, res) {
- /* Process the form uploads */
- if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
- var form = new formidable.IncomingForm();
- form.parse(req, function(err, fields, files) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.write('received upload:\n\n');
- res.end(util.inspect({fields: fields, files: files}));
- });
- return;
- }
- /* Display the file upload form. */
- res.writeHead(200, {'content-type': 'text/html'});
- res.end(
- '<form action="/upload" enctype="multipart/form-data" method="post">'+
- '<input type="text" name="title"><br>'+
- '<input type="file" name="upload" multiple="multiple"><br>'+
- '<input type="submit" value="Upload">'+
- '</form>'
- );
- }).listen(8080);
Couper Node en tapant ctrl+c
puis le relancer avec node app.js
depuis le terminal. Il faudra faire cela à chaque modification du fichier « app.js ».
Ici, on test si l’url est /upload
et la méthode post
et ensuite on utilise la méthode parse
pour analyser la requête node. Ensuite, sont affichés dans le navigateur les détails du résultat de cette analyse grâce à la méthode util.inspect
. Voici ce j’ai obtenu :
- received upload:
- { fields: { title: '' },
- files:
- { upload:
- { domain: null,
- _events: {},
- _maxListeners: 10,
- size: 143372960,
- path: '/tmp/835cfd0595c3c70373ce830f4b0f3d6f',
- name: 'dni-symphonie-noire-140511.flac',
- type: 'audio/flac',
- hash: null,
- lastModifiedDate: Sat May 31 2014 05:38:40 GMT+0200 (CEST),
- _writeStream: [Object] } } }
Comme vous pouvez le voir, le fichier a été téléchargé dans le dossier /tmp/
. Il s’appelle 835cfd0595c3c70373ce830f4b0f3d6f
. Nous avons donc tout ce qu’il nous faut pour copier ce fichier en utilisant NodeJS. Notez la présence d’autres informations qui pourraient ête utile pour divers contrôles.
- var formidable = require('formidable'),
- http = require('http'),
- util = require('util'),
- fs = require('fs-extra'),
- path = require("path");
- http.createServer(function (req, res) {
- /* Process the form uploads */
- if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
- var form = new formidable.IncomingForm();
- form.parse(req, function (err, fields, files) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.write('received upload:\n\n');
- res.end(util.inspect({fields: fields, files: files}));
- });
- form.on('end', function (fields, files) {
- /* Temporary location of our uploaded file */
- var temp_path = this.openedFiles[0].path;
- /* The file name of the uploaded file */
- var file_name = this.openedFiles[0].name;
- /* Location where we want to copy the uploaded file */
- var new_location = path.join(__dirname, '/upload/');
- fs.copy(temp_path, new_location + file_name, function (err) {
- if (err) {
- console.error(err);
- } else {
- console.log("success!")
- }
- });
- });
- return;
- }
- /* Display the file upload form. */
- res.writeHead(200, {'content-type': 'text/html'});
- res.end(
- '<form action="/upload" enctype="multipart/form-data" method="post">' +
- '<input type="text" name="title"><br>' +
- '<input type="file" name="upload" multiple="multiple"><br>' +
- '<input type="submit" value="Upload">' +
- '</form>'
- );
- }).listen(8080);
Ici, est utilisé l’événement end
du module Fomidable pour copier le fichier dans le dossier que l’on veut. L’événement end
est émis lorsque la requête a entièrement été reçue, et tous les fichiers traités
Il est possible de tester les erreurs de téléchargement en se basant sur l’événement error
. Cet événement est émis lorsqu’il y a une erreur lors du traitement du formulaire. Un requête avec une erreur est mise en pause automatiquement. Vous aurez à appeler manuellement request.resume()
pour que la requête continue d’envoyer des données.
- form.on('error', function(err) {
- console.error(err);
- });
Vérifier la progression du téléchargement
Lorsque que sont téléchargés de gros fichiers, il est utile d’indiquer la progression du téléchargement. Formidable rend facile cela. On peut, en effet, utiliser l’événement progress
émis après la réception de chaque paquet de données. Ici, nous affichons la progression seulement dans le terminal.
- form.on('progress', function(bytesReceived, bytesExpected) {
- var percent_complete = (bytesReceived / bytesExpected) * 100;
- console.log(percent_complete.toFixed(2));
- });
Voilà, tout ce qui est nécessaire au téléchargement de fichiers avec NodeJS en utilisant formidable est là ! Voici le code complet :
- var formidable = require('formidable'),
- http = require('http'),
- util = require('util'),
- fs = require('fs-extra'),
- path = require("path");
- http.createServer(function (req, res) {
- /* Process the form uploads */
- if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
- var form = new formidable.IncomingForm();
- form.parse(req, function (err, fields, files) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.write('received upload:\n\n');
- res.end(util.inspect({fields: fields, files: files}));
- });
- form.on('progress', function(bytesReceived, bytesExpected) {
- var percent_complete = (bytesReceived / bytesExpected) * 100;
- console.log(percent_complete.toFixed(2));
- });
- form.on('end', function (fields, files) {
- /* Temporary location of our uploaded file */
- var temp_path = this.openedFiles[0].path;
- /* The file name of the uploaded file */
- var file_name = this.openedFiles[0].name;
- /* Location where we want to copy the uploaded file */
- var new_location = path.join(__dirname, '/upload/');
- fs.copy(temp_path, new_location + file_name, function (err) {
- if (err) {
- console.error(err);
- } else {
- console.log("success!")
- }
- });
- });
- return;
- }
- /* Display the file upload form. */
- res.writeHead(200, {'content-type': 'text/html'});
- res.end(
- '<form action="/upload" enctype="multipart/form-data" method="post">' +
- '<input type="text" name="title"><br>' +
- '<input type="file" name="upload" multiple="multiple"><br>' +
- '<input type="submit" value="Upload">' +
- '</form>'
- );
- }).listen(8080);
Changer le dossier temporaire
Il y a des options de téléchargement que l’on peut modifier dont le dossier qui accueil les fichiers temporaire. On peut faire cela en par l’intermédiaire de l’événement fileBegin
émis lorsqu’une paire champ/valeur a été reçue.
- form.on('fileBegin', function(name, file) {
- file.path = 'c:/localhost/nodejs/uploads/' + file.name;
- });
Le code complet :
- var formidable = require('formidable'),
- http = require('http'),
- util = require('util'),
- fs = require('fs-extra'),
- path = require("path");
- http.createServer(function (req, res) {
- /* Process the form uploads */
- if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
- var form = new formidable.IncomingForm();
- form.parse(req, function (err, fields, files) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.write('received upload:\n\n');
- res.end(util.inspect({fields: fields, files: files}));
- });
- form.on('fileBegin', function(name, file) {
- file.path = path.join(__dirname, '/temp/') + file.name;
- });
- form.on('progress', function(bytesReceived, bytesExpected) {
- var percent_complete = (bytesReceived / bytesExpected) * 100;
- console.log(percent_complete.toFixed(2));
- });
- form.on('end', function (fields, files) {
- /* Temporary location of our uploaded file */
- var temp_path = this.openedFiles[0].path;
- /* The file name of the uploaded file */
- var file_name = this.openedFiles[0].name;
- /* Location where we want to copy the uploaded file */
- var new_location = path.join(__dirname, '/upload/');
- fs.copy(temp_path, new_location + file_name, function (err) {
- if (err) {
- console.error(err);
- } else {
- console.log("success!")
- }
- });
- });
- return;
- }
- /* Display the file upload form. */
- res.writeHead(200, {'content-type': 'text/html'});
- res.end(
- '<form action="/upload" enctype="multipart/form-data" method="post">' +
- '<input type="text" name="title"><br>' +
- '<input type="file" name="upload" multiple="multiple"><br>' +
- '<input type="submit" value="Upload">' +
- '</form>'
- );
- }).listen(8080);
Voici ce qui est affiché sur le navigateur :
- received upload:
- { fields: { title: '' },
- files:
- { upload:
- { domain: null,
- _events: {},
- _maxListeners: 10,
- size: 143372960,
- path: '/home/robomatix/nodejs/testapp/upload-app/temp/dni-symphonie-noire-140511.flac',
- name: 'dni-symphonie-noire-140511.flac',
- type: 'audio/flac',
- hash: null,
- lastModifiedDate: Sat May 31 2014 06:34:30 GMT+0200 (CEST),
- _writeStream: [Object] } } }
On peut noter que le path
est différent de la première fois. Il est maintenant celui que l’on vient de spécifier.
On remarquera que le fichier dans temp
n’est pas effacé...
Il faut donc l’effacer pour ne pas encombrer inutilement le seveur.
Voici comment ce faire :
- // Delete the "temp" file
- fs.unlink(temp_path, function(err) {
- if (err) {
- console.error(err);
- console.log("TROUBLE deletion temp !");
- } else {
- console.log("success deletion temp !");
- }
- });
Le code complet :
- var formidable = require('formidable'),
- http = require('http'),
- util = require('util'),
- fs = require('fs-extra'),
- path = require("path");
- http.createServer(function (req, res) {
- /* Process the form uploads */
- if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
- var form = new formidable.IncomingForm();
- form.parse(req, function (err, fields, files) {
- res.writeHead(200, {'content-type': 'text/plain'});
- res.write('received upload:\n\n');
- res.end(util.inspect({fields: fields, files: files}));
- });
- form.on('fileBegin', function(name, file) {
- file.path = path.join(__dirname, '/temp/') + file.name;
- });
- form.on('progress', function(bytesReceived, bytesExpected) {
- var percent_complete = (bytesReceived / bytesExpected) * 100;
- console.log(percent_complete.toFixed(2));
- });
- form.on('end', function (fields, files) {
- /* Temporary location of our uploaded file */
- var temp_path = this.openedFiles[0].path;
- /* The file name of the uploaded file */
- var file_name = this.openedFiles[0].name;
- /* Location where we want to copy the uploaded file */
- var new_location = path.join(__dirname, '/upload/');
- fs.copy(temp_path, new_location + file_name, function (err) {
- if (err) {
- console.error(err);
- } else {
- console.log("success!");
- // Delete the "temp" file
- fs.unlink(temp_path, function(err) {
- if (err) {
- console.error(err);
- console.log("TROUBLE deletion temp !");
- } else {
- console.log("success deletion temp !");
- }
- });
- }
- });
- });
- return;
- }
- /* Display the file upload form. */
- res.writeHead(200, {'content-type': 'text/html'});
- res.end(
- '<form action="/upload" enctype="multipart/form-data" method="post">' +
- '<input type="text" name="title"><br>' +
- '<input type="file" name="upload" multiple="multiple"><br>' +
- '<input type="submit" value="Upload">' +
- '</form>'
- );
- }).listen(8080);
Et voilà !
Petite précision : normalement, lorsque l’on code avec NodeJS, c’est en mode Code less do more. En Express ou avec Sails ce genre de chose doit prendre pas plus de 20 lignes... C’est juste pour comprendre certains mécanismes...
Vos commentaires
# Le 22 septembre 2018 à 12:39, par Bouftout
J’aurai une question,comment on fait pour limiter la taille du fichier envoyé car si il envoie une trop grosse image ça prend trop de place,merci si vous me répondez
# Le 22 septembre 2018 à 12:40, par Bouftout
Si des personne on express sur leur serveur web en node.js voici comment faut faire
var formidable = require(’formidable’),
util = require(’util’),
fss = require(’fs-extra’),
path = require("path") ;
app.post(’/upload’, function (req, res)
if (req.method.toLowerCase() == ’post’)
var form = new formidable.IncomingForm() ;
form.parse(req, function (err, fields, files)
res.writeHead(200, ’content-type’ : ’text/plain’) ;
res.write(’received upload :\n\n’) ;
res.end(util.inspect(fields : fields, files : files)) ;
) ;
form.on(’fileBegin’, function(name, file)
file.path = path.join(’./temp/’) + file.name ;
) ;
form.on(’progress’, function(bytesReceived, bytesExpected)
var percent_complete = (bytesReceived / bytesExpected) * 100 ;
console.log(percent_complete.toFixed(2)) ;
) ;
# Le 22 septembre 2018 à 12:40, par Bouftout
form.on(’end’, function (fields, files)
/* Temporary location of our uploaded file */
var temp_path = this.openedFiles[0].path ;
/* The file name of the uploaded file */
var file_name = this.openedFiles[0].name ;
/* Location where we want to copy the uploaded file */
var new_location = path.join(__dirname, ’/upload/’) ;
fss.copy(temp_path, new_location + file_name, function (err)
if (err)
console.error(err) ;
else
console.log("success !") ;
// Delete the "temp" file
fss.unlink(temp_path, function(err)
if (err)
console.error(err) ;
console.log("TROUBLE deletion temp !") ;
else
console.log("success deletion temp !") ;
) ;
) ;
) ;
return ;
) ;
# Le 22 septembre 2018 à 12:41, par Bouftout
app.get(’/pageupload’, function(req, res)
/* Display the file upload form. */
res.writeHead(200, ’content-type’ : ’text/html’) ;
res.end(
’
’
) ;
) ;
Répondre à cet article
Tous les champs sont obligatoires
Suivre les commentaires :
|
