web-dev-qa-db-ja.com

Node.jsを使用して、base64でエンコードされた画像(文字列)をGoogle Cloud Storageバケットに直接アップロードするにはどうすればよいですか?

現在、 @ google-cloud/storage NPMパッケージを使用して、Google Cloud Storageバケットにファイルを直接アップロードしています。画像のbase64エンコードされた文字列しか持っていないため、これには多少の工夫が必要です。しなければならない:

  • 文字列をデコードする
  • ファイルとして保存する
  • ファイルパスを以下のスクリプトに送信して、Google Cloud Storageにアップロードします
  • ローカルファイルを削除する

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でエンコードされた画像の文字列を直接アップロードする方法はありますか?

21
Nag

解決策は、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'));

base64のデコード および ストリームの作成 の詳細。

次に、ストリームを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.upload 、および bucket.uploadメソッドに関する情報Node SDKのコード

したがって、上記のコードが機能する方法は、ファイルを配置するバケットを定義してから、ファイルとファイル名を定義することです。ここではアップロードオプションを設定しません。次に、作成したbufferStream変数を、前に説明したfile.createWriteStreamメソッドにパイプします。これらのオプションでは、実装するメタデータおよびその他のオプションを定義します。 Githubのノードコード を直接見て、bucket.upload関数をどのように分解するかを理解し、同様に実行することをお勧めしました。最後に、アップロードの完了時とエラー時のいくつかのイベントを添付します。

30
forrestmid

上記の@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');
});

これは私にとってはうまくいきました。最初の数行の追加ロジックは、私が作成しているアプリケーションにのみ関連しているため、無視してください。

19
Nag