GCSにクライアントからアップロードする
画像、ドキュメント、映像、音声など様々な種類のファイルをクラウドストレージにアップロードするシーンは多々あります。そんなとき クライアント => バックエンド => クラウド の順番にアップロードしていると通信に時間がかかります。そこで、署名付きURLを使って クライアント => クラウド で直接アップロードするといい感じです。
AWSのS3は結構ドキュメントなり記事なりが充実していますが、GCS x Node.js のものがほとんどなく苦労したので残しておきます。
1.署名付きURLを発行(バックエンド)
署名付きURLはGCSのサービスクレデンシャルが必要なのでバックエンドで行います。フレームワークにexpressを使っています。
signed_url.ts
importexpressfrom"express";exportconstpost_signed_url=async(req:express.Request,res:express.Response)=>{const{Storage}=require('@google-cloud/storage');constclient=newStorage();constoptions={version:'v4',action:'write',expires:Date.now()+15*60*1000,contentType:'application/octet-stream',};consturl=awaitclient.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(){constfile=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を指定のようにしないといけません。どんなファイル形式でも。
以上です!