はじめに
ブラウザからサイズの大きいファイルをアップロードしようとした際にCloud Runの容量制限を越えられないため、GCSから署名つきURLを発行してブラウザから直接アップロードしました。
開発環境
- Next.js 14.2.2
- Terraform
- Cloud Run (実行環境)
署名付きURLの発行
index.ts
export async function getSignedUrl(): Promise<string> {
try {
const filePath = "filename.wav";
const storage = new Storage();
const file = storage
.bucket("your_bucket_name")
.file(filePath);
const [signedUrl] = await file.getSignedUrl({
version: "v4",
action: "write",
expires: Date.now() + 24 * 60 * 60 * 1000, // 24 hours
});
return signedUrl;
} catch (error) {
console.error(error);
throw new Error("Failed to get signed URL");
}
}
ブラウザ側からGCSにアップロード
async function uploadDataToGCS(): Promise<string> {
try {
const signedUrl = await getSignedUrl(encodedFileName);
await fetch(signedUrl, {
method: "PUT",
body: value,
});
} catch (error) {
console.error("Error upload file to GCS:", error);
}
}
CORSの設定をしていない場合はエラーになります。必ず設定しましょう。
実際はterraformで実装してますが、動作確認などローカル環境で実行させるにはコンソール、もしくはscriptで直接設定しても良いかもしれません。
storage_bucket.tf
resource "google_storage_bucket" "asset_bucket" {
name = "your-asset-bucket-name"
location = "US"
force_destroy = true
cors {
origin = ["http://localhost:3000"]
method = ["PUT"]
response_header = ["Content-Type"]
max_age_seconds = 3600
}
}
async function configureBucketCors() {
await storage.bucket(bucketName).setCorsConfiguration([
{
maxAgeSeconds,
method: [method],
origin: [origin],
responseHeader: [responseHeader],
},
]);
}
サービスアカウントの権限の設定
権限設定もコンソールから設定できますが、実際はprod,stg,dev等の環境があるはずです。毎回コンソールから設定していてはミスしかねないので、このようにインフラもコード化しておきましょう!
service_account.tf
resource "google_project_iam_member" "service_account_sign_blob" {
project = "<YOUR_PROJECT_ID>"
role = "roles/iam.serviceAccountTokenCreator"
member = "serviceAccount:${google_service_account.my_service_account.email}"
}