2022/07/09
署名付きURLでCloud Storage に画像ファイルを直接アップロードする
署名付きURLとは
概要は公式ドキュメントの「署名付き URL」で説明されています。また「署名付き URL を活用して Cloud Storage に画像ファイルを直接アップロードするアーキテクチャを設計する」にも紹介されています。
署名付き URL 機能を使うことで、英数字の署名トークン付きの URL を知っている人がアクセスできる、時間制限付きの URL を発行することができます。
クエリ文字列内に認証情報が入っているため、 設定された制限時間内であれば URL を知っている誰もが アクセスでき、認証は必要ありません。
何らかの理由で Google アカウントやサービスアカウントによる認証が使えない場面で、限定的なアクセス (オブジェクトのアップロードやダウンロード) を提供したいときに利用します。
署名付き URL は以下のようになります。
https://storage.googleapis.com/example-bucket/cat.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com%2F20181026%2Fus-central1%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T181309Z&X-Goog-Expires=900&X-Goog-SignedHeaders=host&X-Goog-Signature=247a2aa45f169edf4d187d54e7cc46e4731b1e6 (中略) c56c5ca81ff3447032ea7abedc098d2eb14a7
アップロードの流れ
署名付きURLを生成する処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Imports the Google Cloud client library const { Storage } = require('@google-cloud/storage'); const storage = new Storage(); const bucketName = BUCKET_NAME; app.get('/sign_url', async (req, res) => { // These options will allow temporary uploading of the file with outgoing // Content-Type: application/octet-stream header. const options = { version: 'v4', action: 'write', expires: Date.now() + 15 * 60 * 1000, // 15 minutes contentType: req.query.type, extensionHeaders: { "x-goog-resumable":"start", } }; const filename = Date.now() + path.extname(req.query.file); const [url] = await storage.bucket(bucketName).file(filename).getSignedUrl(options); res.send(url); }); |
参考元:https://cloud.google.com/storage/docs/access-control/signing-urls-with-helpers#code-samples
Cloud StorageのバケットにCORS設定をする
バケットの CORS 構成を設定するには、受け入れられるリクエストのタイプを識別する情報(HTTP メソッドや発信元のドメインなど)を指定します。
1 2 3 4 5 6 7 8 | [ { "origin": ["http://example.appspot.com"], "responseHeader": ["Content-Type"], "method": ["*"], "maxAgeSeconds": 3600 } ] |
CORSを設定する
1 | gsutil cors set cors_setting.json gs://[バケット名] |
CORSを確認する
1 | gsutil cors get gs://[バケット名] |
画像ファイルを直接アップロード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <form id="form"> <input id="input_file" type="file"><br> <br> <button id="sign_url">URL発行</button><br><span id="url"></span><br> <br> <button id="upload">署名付きで画像をアップロード</button><br><br> <span >公開URL:</span><br> <span id="url2"></span><br> </form> <script> window.onload = () => { document.querySelector("#sign_url").addEventListener("click", async (e) => { e.preventDefault(); const file = document.querySelector("#input_file").files[0]; // console.log(file); const res = await fetch(`http://localhost:8080/sign_url?file=${file.name}&type=${file.type}`, { method: "GET", }); document.querySelector("#url").innerHTML = await res.text(); }); document.querySelector("#upload").addEventListener("click", async (e) => { e.preventDefault(); const file = document.querySelector("#input_file").files[0]; const url = document.querySelector("#url").innerText; const url2 = url.substr(0, url.indexOf('?')); document.querySelector("#url2").innerText = url2; const response = await fetch(url, { headers: { "Content-Type": file.type, }, method: "PUT", body: file }); if (!response.ok) { console.error('response.ok:', response.ok); console.error('response.status:', response.status); console.error('response.statusText:', response.statusText); throw new Error(response.statusText); } |
アップロード成功したら
アップロード成功したら、バケット内のファイルのページで詳細が見れます。
Author Profile
スターフィールド編集部
SHARE