跳到主要內容
← 回到學習

學習 · 後端與資料庫

CORS firebase

目錄 · 6 個段落
  1. 01錯誤訊息
  2. 02為什麼會被擋
  3. 03解法步驟
  4. 04CORS 完整欄位
  5. 05替代:用 Firebase SDK
  6. 06額外:Cloud Storage 內 metadata 的 CORS 也要

Firebase Cloud Storage CORS 設定

TL;DR
Firebase Storage 跨域下載檔案會被 CORS 擋(出現 Access-Control-Allow-Origin 錯誤)。解法是 透過 gsutil cors set cors.json gs://<bucket> 設定 bucket 的 CORS policy,Firebase 控制台沒有 GUI 能改這個。

錯誤訊息

Access to fetch at 'https://firebasestorage.googleapis.com/v0/b/.../o/...'
from origin 'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.

這個錯出現在:

  • 用 fetch() / XHR 想直接下載 Firebase Storage 上的檔案
  • 想把圖片轉成 Blob、Base64 或 Canvas 處理
  • 跨域 存取(讀取)檔案內容(直接 <img src> 顯示不會踩,因為瀏覽器走另一條路)

為什麼會被擋

Firebase Storage 的 default bucket 沒設 CORS。瀏覽器發 cross-origin fetch 時,server 的 response 沒有 Access-Control-Allow-Origin header → 瀏覽器拒絕該請求。

為什麼 <img> 不會踩
<img> / <video> 等 tag-based 載入是 simple request,不走 CORS preflight,所以能正常顯示。但要把圖內容讀進 Canvas / 轉 Base64 就要 CORS,crossorigin="anonymous" + bucket CORS 設定都要。

解法步驟

1. 建立 cors.json

[
  {
    "origin": ["*"],
    "method": ["GET"],
    "maxAgeSeconds": 3600
  }
]
json
"origin": ["*"] 是允許所有網域
正式環境建議改成具體網域:
"origin": ["https://yourdomain.com", "https://staging.yourdomain.com", "http://localhost:3000"]
json

2. 安裝 gsutil(Google Cloud SDK)

# macOS / Linux
curl https://sdk.cloud.google.com | bash
# 或 brew install google-cloud-sdk
 
# Windows:下載 installer
# https://cloud.google.com/sdk/docs/install
bash

3. 認證 + 設定 CORS

# 一次性登入
gcloud auth login
 
# 設定 CORS
gsutil cors set cors.json gs://your-project-id.appspot.com
bash

bucket 名通常是 <project-id>.appspot.com 或 <project-id>.firebasestorage.app(2024+ 新建專案)。在 Firebase Console → Storage 看上方就能找到。

4. 驗證

gsutil cors get gs://your-project-id.appspot.com
bash

應該回傳你剛設的 JSON。CORS 設定即時生效,但 瀏覽器 cache 可能要 hard reload(Cmd+Shift+R / Ctrl+Shift+R) 才看得到效果。


CORS 完整欄位

[
  {
    "origin": ["https://example.com"],
    "method": ["GET", "POST", "DELETE"],
    "responseHeader": ["Content-Type", "Authorization"],
    "maxAgeSeconds": 3600
  }
]
json
欄位說明
origin允許的來源網域
method允許的 HTTP 方法
responseHeader允許 client 讀取的 response header
maxAgeSecondspreflight 結果 cache 時間(秒)
一個 cors.json 多個 rule
可以針對不同 origin 設不同 method:
[
  { "origin": ["https://prod.com"], "method": ["GET"] },
  { "origin": ["http://localhost:3000"], "method": ["GET", "POST"] }
]
json

替代:用 Firebase SDK

如果用 Firebase SDK 的 getDownloadURL + fetch,SDK 會幫你處理一些事,但 fetch(downloadURL) 仍會踩 CORS。最好還是設 bucket CORS。

import { getStorage, ref, getDownloadURL } from 'firebase/storage';
 
const storage = getStorage();
const fileRef = ref(storage, 'images/photo.jpg');
const url = await getDownloadURL(fileRef);
 
const response = await fetch(url);   // ⚠️ 仍需 CORS 允許
const blob = await response.blob();
typescript

額外:Cloud Storage 內 metadata 的 CORS 也要

下載連結內含 access token,token 過期就 401。如果你的應用會 cache 連結,記得處理 連結重新生成 的邏輯,否則重啟後讀舊連結會壞。

參考

目錄