LoginSignup
6
6

More than 3 years have passed since last update.

Node.js で Google Cloud Storage に署名付きURLを使ってファイルアップロードする方法

Last updated at Posted at 2020-08-15

GCSにクライアントからアップロードする

画像、ドキュメント、映像、音声など様々な種類のファイルをクラウドストレージにアップロードするシーンは多々あります。そんなとき クライアント => バックエンド => クラウド の順番にアップロードしていると通信に時間がかかります。そこで、署名付きURLを使って クライアント => クラウド で直接アップロードするといい感じです。

AWSのS3は結構ドキュメントなり記事なりが充実していますが、GCS x Node.js のものがほとんどなく苦労したので残しておきます。

1.署名付きURLを発行(バックエンド)

署名付きURLはGCSのサービスクレデンシャルが必要なのでバックエンドで行います。フレームワークにexpressを使っています。

signed_url.ts
import express from "express";

export const post_signed_url = async (req: express.Request, res: express.Response) => {
  const {Storage} = require('@google-cloud/storage');

  const client = new Storage();

  const options = {
    version: 'v4',
    action: 'write',
    expires: Date.now() + 15 * 60 * 1000,
    contentType: 'application/octet-stream',
  };

  const url = await client.bucket("your_bucket_name").file(req.body.file_name).getSignedUrl(options);

  res.send(url)
}

ポイントはcontentTypeです。上記のように'application/octet-stream'にしないといけません。

2.署名付きURLを取得(クライアント)

1で作ったAPIを叩いて署名付きURLを取得します。
file_nameにはアップロードするファイルの名前を入れます。

get_signed_url.ts
post_signed_url () {
  this.$axios.post('/api/post_url', {
    file_name: "your_uploading_file.png"
  }).then((res: any) => {
    this.signed_url = res.data[0]
  })
}

3.アップロードできるようにバケットのCORSを設定します。

上記で取得したurlをそのまま使ってもCORSではじかれてしまうので設定します。

3.1. 好きなディレクトリで下記ファイルをつくります。ファイル名は自由です。

cors.json
[
  {
    "origin": ["http://localhost:3000"],
    "responseHeader": ["Content-Type", "Authorization",  "Content-Length", "User-Agent", "x-goog-resumable"],
    "method": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    "maxAgeSeconds": 3600
  }
]

3.2 さっき作ったファイルを指定してバケットに設定します。

$ gsutil cors set cors.json gs://your_bucket_name

以下のコマンドで設定を確認できます。

$ gsutil cors get gs://your_bucket_name

4.クライアントからアップロードします。

変数 signed_url には2で取得したものを設定します。

client.js
upload_file () {
  const file = document.querySelector('#file').files[0];
  if (signed_url != null && target != undefined) {
    this.$axios.put(signed_url,
    file,
    {
      headers: {
      'Content-Type': 'application/octet-stream'
    }
  }).then((res: any) => {
    console.log(res)
  })
}

クライアント側でもContent-Typeを指定のようにしないといけません。どんなファイル形式でも。

以上です!

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6