1
votes

Envoi de plusieurs fichiers vers Google Bucket avec Multer - Pourquoi mes fichiers sont-ils vides?

Auparavant, un seul téléchargement de fichier était configuré et fonctionnait correctement. Maintenant, je dois lui faire gérer plusieurs fichiers.

Voici mon code en ce moment:

function sendUploadToGCS (req, res, next) {
  if (!req.file) {
    return next();
  }

  const gcsname = Date.now() + req.file.originalname;
  const file = bucket.file(gcsname);

  const stream = file.createWriteStream({
    metadata: {
      contentType: req.file.mimetype
    },
    resumable: false
  });

  stream.on('error', (err) => {
    req.file.cloudStorageError = err;
    next(err);
  });

  stream.on('finish', () => {
    req.file.cloudStorageObject = gcsname;
    file.makePublic().then(() => {
      req.file.cloudStoragePublicUrl = getPublicUrl(gcsname);
      next();
    });
  });

  stream.end(req.file.buffer);
}

req.files me donne un tableau de fichiers, avec un tampon et une taille qui a du sens. Les promesses se résolvent toutes. Mais une fois que j'ai vérifié les fichiers dans le bucket google, ils ont le bon nom mais n'ont pas de contenu (et une taille de 0)

Comme je l'ai déjà dit, cela fonctionnait quand je le faisais avec un fichier (en utilisant m.single ('file')

Je ne veux pas utiliser le bucket comme destination avec la configuration de multer, car je dois également changer le nom du fichier avant de le télécharger dans google bucket.

edit: c'est l'exemple de code donné par les documentations google cloud pour les téléchargements de fichiers uniques ( https://cloud.google.com/nodejs/getting-started/using-cloud-storage ):

const multer = require('multer')
const { Storage } = require('@google-cloud/storage')

const storage = new Storage()

const m = multer({ storage: multer.memoryStorage()  })

module.exports = app => {
  app.use('/', router)
  router.post(
    '/reader-:shortId/file-upload',
    passport.authenticate('jwt', { session: false }),
    m.array('files'),
    async function (req, res) {
      const bucketName = req.params.shortId.toLowerCase()
      await storage.createBucket(bucketName)
      bucket = storage.bucket(bucketName)
      let promises = []

      req.files.forEach((file) => {
        const blob = bucket.file(file.originalname)
        const newPromise =  new Promise((resolve, reject) => {
          blob.createWriteStream({
            metadata: { contentType: file.mimetype }
          }).on('finish', async response => {
            await blob.makePublic()
            resolve(response)
          }).on('error', err => {
            reject('upload error: ', err)
          }).end()
        })
       promises.push(newPromise)
     })

     Promise.all(promises).then((response) => {
       // the response I get here is [undefined, undefined]
       res.status(200).send(response)
     }).catch((err) => {
       res.status(400).send(err.message)
     });
    })
  }

I À l'origine, quelque chose comme ça fonctionnait, mais je ne comprends tout simplement pas d'où proviennent les données du tampon de fichier. C'est probablement là que les choses sont différentes avec plusieurs fichiers.


1 commentaires

Je ne vois pas où vous écrivez réellement le contenu du fichier . Les seules propriétés du fichier que je vois en cours d'utilisation sont originalname et mimetype .


3 Réponses :


1
votes

Ok, il s'est avéré que j'ai dû changer .end () à .end(file.buffer)


0 commentaires

1
votes

Je sais qu'il est trop tard, mais quelqu'un pourrait chercher une réponse pour importer plusieurs fichiers sur Google Cloud Storage.

Dépendances:

  • Express
  • Bibliothèque Google Cloud
  • Multer
  • Analyseur corporel

Voici le code du contrôleur.

exports.post_image_upload = async (req, res) => {
   /** Check if file exist */
   if (!req.files) {
       res.status(400).send('No file uploaded.');
       return;
   }

   let PublicUrls = []

   req.files.forEach((file) => {
       const blob = bucket.file(file.fieldname + '-' + Date.now() + path.extname(file.originalname))

       const blobStream = blob.createWriteStream({
           metadata: { contentType: file.mimetype }
       })
       blobStream.on('finish', ()=> {
           blob.makePublic()           
       })
       blobStream.on('error', err => {
           //Put your error message here
       })
       blobStream.end(file.buffer)

       const Url = `https://storage.googleapis.com/${bucket.name}/${blob.name}`

       PublicUrls.push(Url)
   })

   res.send(PublicUrls)
}

Bonne chance


0 commentaires

0
votes

Marie Pelletier, je pense que votre approche est à 100% juste. J'ai modifié un peu votre code en essayant d'éviter la réponse asynchrone:

let promises = []
req.files.forEach((file) => {
  const blob = bucket.file(file.originalname)
  const newPromise =  new Promise((resolve, reject) => {
    blob.createWriteStream({
      metadata: { contentType: file.mimetype },
      resumable: false //Good for small files
    }).on('finish', () => {
      const Url = `https://storage.googleapis.com/${bucket.name}/${blob.name}`;
      resolve({ name: file.originalname, url: Url });
    }).on('error', err => {
      reject('upload error: ', err);
    }).end(file.buffer);
  })
  promises.push(newPromise);
})

Promise.all(promises).then((response) => {
  res.status(200).send(response)
}).catch((err) => {
  res.status(400).send(err.message)
});

De cette façon, je ne suis plus "indéfini".


0 commentaires