web-dev-qa-db-fra.com

Comment télécharger une image (chaîne) encodée en base64 directement dans un compartiment Google Cloud Storage à l'aide de Node.js?

Actuellement, j'utilise le package @ google-cloud/storage NPM pour télécharger un fichier directement dans un bucket Google Cloud Storage. Cela nécessite une ruse car je n'ai que la chaîne encodée en base64 de l'image. Je dois:

  • Décode la chaîne
  • Enregistrez-le en tant que fichier
  • Envoyez le chemin du fichier au script ci-dessous pour le télécharger sur Google Cloud Storage
  • Supprimer le fichier local

Je voudrais éviter de stocker le fichier dans le système de fichiers car j'utilise Google App Engine et je ne veux pas surcharger le système de fichiers/laisser des fichiers inutiles si l'opération de suppression ne fonctionne pas pour une raison quelconque. Voici à quoi ressemble mon script de téléchargement en ce moment:

// Convert the base64 string back to an image to upload into the Google Cloud Storage bucket
var base64Img = require('base64-img');
var filePath = base64Img.imgSync(req.body.base64Image, 'user-uploads', 'image-name');

// Instantiate the GCP Storage instance
var gcs = require('@google-cloud/storage')(),
    bucket = gcs.bucket('google-cloud-storage-bucket-name');

// Upload the image to the bucket
bucket.upload(__dirname.slice(0, -15) + filePath, {
    destination: 'profile-images/576dba00c1346abe12fb502a-original.jpg',
    public: true,
    validation: 'md5'
}, function(error, file) {

    if (error) {
        sails.log.error(error);
    }

    return res.ok('Image uploaded');
});

Existe-t-il de toute façon de télécharger directement la chaîne encodée en base64 de l'image au lieu d'avoir à la convertir en fichier, puis à télécharger à l'aide du chemin?

21
Nag

Je pense que la solution consiste à utiliser le file.createWriteStream fonctionnalité que bucket.upload la fonction s'enroule dans Google Cloud Node SDK.

J'ai très peu d'expérience avec les streams, alors essayez de me supporter si cela ne fonctionne pas tout de suite.

Tout d'abord, nous devons prendre les données base64 et les déposer dans un flux. Pour cela, nous allons inclure la bibliothèque stream, créer un tampon à partir des données base64 et ajouter le tampon à la fin du flux.

var stream = require('stream');
var bufferStream = new stream.PassThrough();
bufferStream.end(Buffer.from(req.body.base64Image, 'base64'));

Plus sur décodage base64 et création du flux .

Nous allons ensuite diriger le flux dans un flux d'écriture créé par le file.createWriteStream une fonction.

var gcs = require('@google-cloud/storage')({
  projectId: 'grape-spaceship-123',
  keyFilename: '/path/to/keyfile.json'
});

//Define bucket.
var myBucket = gcs.bucket('my-bucket');
//Define file & file name.
var file = myBucket.file('my-file.jpg');
//Pipe the 'bufferStream' into a 'file.createWriteStream' method.
bufferStream.pipe(file.createWriteStream({
    metadata: {
      contentType: 'image/jpeg',
      metadata: {
        custom: 'metadata'
      }
    },
    public: true,
    validation: "md5"
  }))
  .on('error', function(err) {})
  .on('finish', function() {
    // The file upload is complete.
  });

Infos sur file.createWriteStream , Documents de fichier , bucket.upload , et le bucket.upload code de méthode dans le Node SDK .

Ainsi, la façon dont le code ci-dessus fonctionne consiste à définir le compartiment dans lequel vous souhaitez placer le fichier, puis à définir le fichier et le nom du fichier. Nous ne définissons pas d'options de téléchargement ici. Nous redirigeons ensuite la variable bufferStream que nous venons de créer dans la file.createWriteStream méthode dont nous avons discuté auparavant. Dans ces options, nous définissons les métadonnées et les autres options que vous souhaitez implémenter. Il a été très utile de regarder directement le Node code on Github pour comprendre comment ils décomposent le bucket.upload, et nous vous recommandons de le faire également. Enfin, nous attachons quelques événements pour quand le téléchargement se termine et quand il se trompe.

30
forrestmid

Publier ma version de la réponse en réponse à la demande de @krlozadan ci-dessus:

// Convert the base64 string back to an image to upload into the Google Cloud Storage bucket
var mimeTypes = require('mimetypes');

var image = req.body.profile.image,
    mimeType = image.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/)[1],
    fileName = req.profile.id + '-original.' + mimeTypes.detectExtension(mimeType),
    base64EncodedImageString = image.replace(/^data:image\/\w+;base64,/, ''),
    imageBuffer = new Buffer(base64EncodedImageString, 'base64');

// Instantiate the GCP Storage instance
var gcs = require('@google-cloud/storage')(),
    bucket = gcs.bucket('my-bucket');

// Upload the image to the bucket
var file = bucket.file('profile-images/' + fileName);

file.save(imageBuffer, {
    metadata: { contentType: mimeType },
    public: true,
    validation: 'md5'
}, function(error) {

    if (error) {
        return res.serverError('Unable to upload the image.');
    }

    return res.ok('Uploaded');
});

Cela a très bien fonctionné pour moi. Ignorez une partie de la logique supplémentaire dans les premières lignes car elles ne concernent que l'application que je construis.

19
Nag