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

时间:2017-03-18 19:42:33

标签: javascript node.js google-cloud-storage google-cloud-platform

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

  • 解码字符串
  • 将其另存为文件
  • 将文件路径发送到以下脚本以上传到Google云端存储
  • 删除本地文件

我想避免将文件存储在文件系统中,因为我使用的是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');
});

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

6 个答案:

答案 0 :(得分:28)

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

我对溪流的经验很少,所以如果不能立即使用,请尽量忍受。

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

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

有关decoding base64creating the stream的详情。

然后我们将流传输到由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.
  });

有关file.createWriteStreamFile docsbucket.uploadbucket.upload method code in the Node SDK的信息。

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

答案 1 :(得分:15)

根据@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');
});

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

答案 2 :(得分:4)

如果要将字符串另存为文件到Google Cloud Storage中,可以使用file.save方法轻松实现:

const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
const myBucket = storage.bucket('my-bucket');

const file = myBucket.file('my-file.txt');
const contents = 'This is the contents of the file.';

file.save(contents).then(() => console.log('done'));

答案 3 :(得分:2)

您必须将base64转换为图像缓冲区,然后按以下方式上传,您需要提供image_data_from_html变量作为从HTML事件中提取的数据。

const base64Text = image_data_from_html.split(';base64,').pop();
const imageBuffer = Buffer.from(base64Text, 'base64');
const contentType = data.image_data.split(';base64,')[0].split(':')[1];
const fileName = 'myimage.png';
const imageUrl = 'https://storage.googleapis.com/bucket-url/some_path/' + fileName;

await admin.storage().bucket().file('some_path/' + fileName).save(imageBuffer, {
    public: true,
    gzip: true,
    metadata: {
        contentType,
        cacheControl: 'public, max-age=31536000',
    }
});

console.log(imageUrl);

答案 4 :(得分:0)

:)什么问题!尝试过并遇到问题图像已上传到Firebase存储上,但未下载,只是加载器在四处移动...花了时间之后...成功将图像上传到Firebase存储中并进行了下载...访问令牌中的问题...

check the screenshot

enter image description here

如果您在右下角的文件位置部分中签入,则有一个选项“创建访问令牌”,并且如果您在那里手动创建访问令牌,则不显示任何“访问令牌”,然后刷新页面图像将显示...所以现在的问题是如何通过代码创建它...

只需使用下面的代码创建访问令牌

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
metadata: { firebaseStorageDownloadTokens: uuid }

下面给出了完整的代码,用于将图像上传到Firebase存储上的存储图像

const functions = require('firebase-functions')
var firebase = require('firebase');
var express = require('express');
var bodyParser = require("body-parser");

enter image description here

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();

    const os = require('os')
    const path = require('path')
    const cors = require('cors')({ origin: true })
    const Busboy = require('busboy')
    const fs = require('fs')
    var admin = require("firebase-admin");


    var serviceAccount = {
        "type": "service_account",
        "project_id": "xxxxxx",
        "private_key_id": "xxxxxx",
        "private_key": "-----BEGIN PRIVATE KEY-----\jr5x+4AvctKLonBafg\nElTg3Cj7pAEbUfIO9I44zZ8=\n-----END PRIVATE KEY-----\n",
        "client_email": "xxxx@xxxx.iam.gserviceaccount.com",
        "client_id": "xxxxxxxx",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
      }

    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        storageBucket: "xxxxx-xxxx" // use your storage bucket name
    });


    const app = express();
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
app.post('/uploadFile', (req, response) => {
    response.set('Access-Control-Allow-Origin', '*');
    const busboy = new Busboy({ headers: req.headers })
    let uploadData = null
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        const filepath = path.join(os.tmpdir(), filename)
        uploadData = { file: filepath, type: mimetype }
        console.log("-------------->>",filepath)
        file.pipe(fs.createWriteStream(filepath))
      })

      busboy.on('finish', () => {
        const bucket = admin.storage().bucket();
        bucket.upload(uploadData.file, {
            uploadType: 'media',
            metadata: {
              metadata: { firebaseStorageDownloadTokens: uuid,
                contentType: uploadData.type,
              },
            },
          })

          .catch(err => {
            res.status(500).json({
              error: err,
            })
          })
      })
      busboy.end(req.rawBody)
   });




exports.widgets = functions.https.onRequest(app);

答案 5 :(得分:0)

我只需一行代码就可以将base64字符串转移到Cloud Storage存储桶中。

var decodedImage = new Buffer(poster64, 'base64');
        

// Store Poster to storage
let posterFile = await client.file(decodedImage, `poster_${path}.jpeg`, { path: 'submissions/dev/', isBuffer: true, raw: true });
let posterUpload = await client.upload(posterFile, { metadata: { cacheControl: 'max-age=604800' }, public: true, overwrite: true });
let permalink = posterUpload.permalink

需要注意的是,如果您处于Nodejs环境中,则将无法使用atob()。

这篇文章的最高答案向我展示了我的方式中的错误! NodeJS base64 image encoding/decoding not quite working