如何使用Node.js将base64编码图像(字符串)直接上传到Google Cloud Storage存储桶?

时间:2021-06-16 20:21:50

Currently, I am using the @google-cloud/storage NPM package to upload a file directly to a Google Cloud Storage bucket. This requires some trickery as I only have the image's base64 encoded string. I have to:

目前,我正在使用@ google-cloud / storage NPM软件包将文件直接上传到Google云端存储分区。这需要一些技巧,因为我只有图像的base64编码字符串。我不得不:

  • Decode the string
  • 解码字符串

  • Save it as a file
  • 将其另存为文件

  • Send the file path to the below script to upload to Google Cloud Storage
  • 将文件路径发送到以下脚本以上传到Google云端存储

  • Delete the local file
  • 删除本地文件

I'd like to avoid storing the file in the filesystem altogether since I am using Google App Engine and I don't want to overload the filesystem / leave junk files there if the delete operation doesn't work for whatever reason. This is what my upload script looks like right now:

我想避免将文件存储在文件系统中,因为我使用的是Google App Engine,如果删除操作因任何原因无效,我不想重载文件系统/留下垃圾文件。这就是我的上传脚本现在的样子:

// 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');
});

Is there anyway to directly upload the base64 encoded string of the image instead of having to convert it to a file and then upload using the path?

反正是否有直接上传图像的base64编码字符串而不必将其转换为文件,然后使用路径上传?

2 个解决方案

#1


18  

The solution, I believe, is to use the file.createWriteStream functionality that the bucket.upload function wraps in the Google Cloud Node SDK.

我相信,解决方案是使用bucket.upload函数在Google Cloud Node SDK中包含的file.createWriteStream功能。

I've got very little experience with streams, so try to bear with me if this doesn't work right off.

我对溪流的经验很少,所以如果不能正常工作,请尽量忍受。

First of all, we need take the base64 data and drop it into a stream. For that, we're going to include the stream library, create a buffer from the base64 data, and add the buffer to the end of the stream.

首先,我们需要获取base64数据并将其放入流中。为此,我们将包括流库,从base64数据创建缓冲区,并将缓冲区添加到流的末尾。

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

More on decoding base64 and creating the stream.

有关解码base64和创建流的更多信息。

We're then going to pipe the stream into a write stream created by the file.createWriteStream function.

然后我们将流传输到由file.createWriteStream函数创建的写入流中。

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.
  });

Info on file.createWriteStream, File docs, bucket.upload, and the bucket.upload method code in the Node SDK.

有关file.createWriteStream,File docs,bucket.upload以及Node SDK中的bucket.upload方法代码的信息。

So the way the above code works is to define the bucket you want to put the file in, then define the file and the file name. We don't set upload options here. We then pipe the bufferStream variable we just created into the file.createWriteStream method we discussed before. In these options we define the metadata and other options you want to implement. It was very helpful to look directly at the Node code on Github to figure out how they break down the bucket.upload function, and recommend you do so as well. Finally, we attach a couple events for when the upload finishes and when it errors out.

因此,上述代码的工作方式是定义要放入文件的存储桶,然后定义文件和文件名。我们不在此处设置上传选项。然后我们将刚刚创建的bufferStream变量传递给我们之前讨论过的file.createWriteStream方法。在这些选项中,我们定义了您要实现的元数据和其他选项。直接查看Github上的Node代码以了解它们如何分解bucket.upload函数非常有帮助,并建议您也这样做。最后,我们附上一些事件,以便在上传完成时和错误输出时。

#2


4  

Posting my version of the answer in response to @krlozadan 's request above:

发布我的答案版本以响应@krlozadan的上述要求:

// 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');
});

This worked just fine for me. Ignore some of the additional logic in the first few lines as they are only relevant to the application I am building.

这对我来说很好。忽略前几行中的一些额外逻辑,因为它们仅与我正在构建的应用程序相关。

#1


18  

The solution, I believe, is to use the file.createWriteStream functionality that the bucket.upload function wraps in the Google Cloud Node SDK.

我相信,解决方案是使用bucket.upload函数在Google Cloud Node SDK中包含的file.createWriteStream功能。

I've got very little experience with streams, so try to bear with me if this doesn't work right off.

我对溪流的经验很少,所以如果不能正常工作,请尽量忍受。

First of all, we need take the base64 data and drop it into a stream. For that, we're going to include the stream library, create a buffer from the base64 data, and add the buffer to the end of the stream.

首先,我们需要获取base64数据并将其放入流中。为此,我们将包括流库,从base64数据创建缓冲区,并将缓冲区添加到流的末尾。

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

More on decoding base64 and creating the stream.

有关解码base64和创建流的更多信息。

We're then going to pipe the stream into a write stream created by the file.createWriteStream function.

然后我们将流传输到由file.createWriteStream函数创建的写入流中。

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.
  });

Info on file.createWriteStream, File docs, bucket.upload, and the bucket.upload method code in the Node SDK.

有关file.createWriteStream,File docs,bucket.upload以及Node SDK中的bucket.upload方法代码的信息。

So the way the above code works is to define the bucket you want to put the file in, then define the file and the file name. We don't set upload options here. We then pipe the bufferStream variable we just created into the file.createWriteStream method we discussed before. In these options we define the metadata and other options you want to implement. It was very helpful to look directly at the Node code on Github to figure out how they break down the bucket.upload function, and recommend you do so as well. Finally, we attach a couple events for when the upload finishes and when it errors out.

因此,上述代码的工作方式是定义要放入文件的存储桶,然后定义文件和文件名。我们不在此处设置上传选项。然后我们将刚刚创建的bufferStream变量传递给我们之前讨论过的file.createWriteStream方法。在这些选项中,我们定义了您要实现的元数据和其他选项。直接查看Github上的Node代码以了解它们如何分解bucket.upload函数非常有帮助,并建议您也这样做。最后,我们附上一些事件,以便在上传完成时和错误输出时。

#2


4  

Posting my version of the answer in response to @krlozadan 's request above:

发布我的答案版本以响应@krlozadan的上述要求:

// 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');
});

This worked just fine for me. Ignore some of the additional logic in the first few lines as they are only relevant to the application I am building.

这对我来说很好。忽略前几行中的一些额外逻辑,因为它们仅与我正在构建的应用程序相关。