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を指定のようにしないといけません。どんなファイル形式でも。
以上です!