11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous,
je viens vers vous car je sèche...

Sur une page html j'ai 2 input de type 'file' ("bigFile" et "smallFile") qui ne sont pas dans un formulaire et un bouton qui appelle une fonction ("ajout()").

Voici ma fonction (les inputs ont été déclarés plus haut dans mon fichier) :
function ajout() {
    if (bigFile.value || smallFile.value) {
        const head3 = {
            method: 'POST',
            body: JSON.stringify({'imageUrl1': bigFile.value, 'imageUrl2': smallFile.value}),
            headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionStorage.token}`}
        }
        fetch('http://localhost:4000/api/caroussel/', head3)
            .then(reponse => {
                if (reponse.status == 200) {
                    alert('Nouvelles images ajoutées avec succès !')
                }
                else {
                    return reponse.json({message: "Erreur"});
                }
            })
            .catch(e => {
                console.log("ça n'a pas marché...")
            })
    }
}


Le back-end reçoit bien la requête mais j'ai un souci avec multer. Voici le code du middleware :
const multer = require('multer');
const MIME_TYPES = {
    'image/jpg': 'jpg',
    'image/jpeg': 'jpg',
    'image/png': 'png',
    'image/bmp': 'bmp',
    'image/webp': 'webp',
    'image/tiff': 'tiff',
    'image/gif': 'gif'
};
const storage = multer.diskStorage({
    destination: (req, file, callback) => {
        callback(null, 'images');
    },
    filename: (req, file, callback) => {
        const name = file.originalname.split(' ').join('_').split('.')[0];
        const extension = MIME_TYPES[file.mimetype];
        callback(null, name + Date.now() + '.' + extension);
    }
});
module.exports = multer({storage}).single('image');


A la sortie je me retrouve avec le chemin initial des images et non les fichiers renommés et rien ne s'upload.

Je me demande si le problème ne viendrait pas du fait que multer reçoit des 'String' au lieu de 'file' mais je ne suis pas sûr.
Qu'en pensez-vous ?
Salut

un peu compliqué de t'aidé.. ce code ne vient pas de toi, essaye de le debugger un peu Smiley biggrin et revient vers nous quand tu auras tous les indices (message d'erreurs par exemple)

le seul truc que ta changé par rapport au code original c'est cette ligne :
file.originalname.split(' ').join('_').split('.')[0]


comment par là. Essaye de debugger ça et dit nous
Modifié par JENCAL (19 Jan 2023 - 10:02)
Je confirme que ce code n'est pas de moi. Je l'ai récupéré lors de ma formation openclassrooms. J'ai utilisé ce code dans plusieurs de mes précédents projets et il fonctionnait nickel.
La première différence avec mes projets précédents c'est qu'aujourd'hui je veux uploader 2 images de 2 input différents (qui ne sont pas dans un formulaire).

J'ai corrigé une première erreur. Je récupérai la valeur des input au lieu de récupérer les files.
Je crois qu'il faut procéder étape par étape car il y a quelques que chose que je n'ai pas compris apparemment (sinon je ne serais pas là ! mdr).

Voici ce que contient mon fichier .js côté front :

const bigFile = document.getElementById('bigFile').files[0];
const smallFile = document.getElementById('smallFile').files[0];

function ajout() {
    if (bigFile || smallFile) {
        if (!bigFile) {
            alert('Vous devez charger 2 fichiers image');
        }
        if (!smallFile) {
            alert('Vous devez charger 2 fichiers image');
        }

        const head3 = {
            method: 'POST',
            body: JSON.stringify({'imageUrl1': bigFile, 'imageUrl2': smallFile}),
            headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionStorage.token}`}
        }
        
        fetch('http://localhost:4000/api/caroussel/', head3)
            .then(reponse => {
                if (reponse.status == 200) {
                    alert('Nouvelles images ajoutées avec succès !')
                }
                else {
                    return reponse.json({message: "Ne fonctionne pas"});
                }
            })
            .catch(e => {
                console.log("ça n'a pas marché...")
            })
    }
}


Côté client la requête échoue puisque je reçois un "ça n'a pas marché" dans la console.
La première question que je me pose. Est-ce que je me trompe dans ma façon d'envoyer mes 2 fichiers au backend ? Je ne suis pas convaincu que ma déclaration du body dans 'head3' soit bonne.
Une chose est sûre c'est que quand je demande au controller de m'afficher le body j'ai :
{ imageUrl1: {}, imageUrl2: {} }

Les imageUrl sont vides...
Y'a un passage par multer avant d'arriver au controller. Mais avant d'incriminer multer, faudrait que je sois sûr qu'il reçoit bien les fichiers...

En tout cas, merci d'avance pour votre aide.
Salut !

Je viens faire une mise à jour de mon problème car il y a du nouveau.

- Tout d'abord, j'ai testé mon backend avec Postman. Je crée une requête POST authentifiée dans laquelle j'ai mis 2 fichiers images. Résultats : les 2 fichiers s'uploadent bien et leur référence s'inscrit dans la bdd. J'en déduit que mon back est fonctionnel.

- Côté front, j'ai modifié un petit peu le body de ma requête :
function ajout() {
    if (bigFile || smallFile) {
        if (!bigFile) {
            alert('Vous devez charger 2 fichiers image');
        }
        if (!smallFile) {
            alert('Vous devez charger 2 fichiers image');
        }

        const fdata = new FormData();
        fdata.append('imageUrlBig', bigFile);
        fdata.append('imageUrlSmall', smallFile);
 
        const head3 = {
            method: 'POST',
            body: fdata,
            headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${sessionStorage.token}`}
        }

        fetch('http://localhost:4000/api/caroussel/', head3)
            .then(reponse => {
                if (reponse.status == 200) {
                    alert('Nouvelles images ajoutées avec succès !')
                }
                else {
                    return reponse.json({message: "Ne fonctionne pas"});
                }
            })
            .catch(e => {
                console.log("ça n'a pas marché...")
            })
    }
}


Comme vous pouvez le voir j'ai utilisé un formData.
A ce jour ça ne fonctionne toujours pas. La console du navigateur me renvoie "ça n'a pas marché...".
Le server crash et me renvoie l'erreur suivante :
PayloadTooLargeError: request entity too large
    at readStream (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/raw-body/index.js:156:17)
    at getRawBody (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/raw-body/index.js:109:12)
    at read (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/body-parser/lib/read.js:79:3)
    at jsonParser (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/body-parser/lib/types/json.js:135:5)
    at Layer.handle [as handle_request] (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/express/lib/router/index.js:328:13)
    at /media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/express/lib/router/index.js:286:9
    at Function.process_params (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/express/lib/router/index.js:346:12)
    at next (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/express/lib/router/index.js:280:10)
    at expressInit (/media/yo/StorageOnBoard/Projets gités/SkiMPlait/SkimPlait/back-end/node_modules/express/lib/middleware/init.js:40:5)


Les images que j'ai posté pèsent 450ko max donc je ne pense pas que ce soit ça le problème. Avez-vous une idée de pourquoi j'ai cette erreur et comment y remédier ?

Merci d'avance !
Pour contourner l'erreur, dans mon fichier app.js j'ai modifié
app.use(express.json());

en
app.use(express.json({limit: '5mb'}));


Du coup j'ai une autre erreur :
SyntaxError: Unexpected token '-', "#" is not valid JSON


De plus en plus obscur pour moi...
J'ai trouvé la solution.
En fait, il fallait bien utiliser un formData. Par contre, du coup, il ne faut plus mettre "Content-Type: application/json" dans les headers. C'est ça qui me renvoyait les messages "Payload To Large" et "unexpected token...". Le navigateur s'occupe de transmettre le bon header c'est pour ça qu'il n'est pas nécessaire de remplacer le Content-Type par autre chose.
Egalement, à la dernière ligne du middleware multer, il faut remplacer "single('image')" par "any('image')".

C'est peut-être basique pour beaucoup mais perso ça m'a fait perdre beaucoup de temps. Comme quoi il reste toujours quelques chose à apprendre...

En espérant que mes déboires (et leur solution) servent à d'autres. Smiley cligne
Modifié par Vahia (21 Jan 2023 - 18:25)