CORS firebase
Firebase Cloud Storage CORS 設定
TL;DRFirebase 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
}
]
"origin": ["*"] 是允許所有網域正式環境建議改成具體網域:"origin": ["https://yourdomain.com", "https://staging.yourdomain.com", "http://localhost:3000"]
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
3. 認證 + 設定 CORS
# 一次性登入
gcloud auth login
# 設定 CORS
gsutil cors set cors.json gs://your-project-id.appspot.com
bucket 名通常是 <project-id>.appspot.com 或 <project-id>.firebasestorage.app(2024+ 新建專案)。在 Firebase Console → Storage 看上方就能找到。
4. 驗證
gsutil cors get gs://your-project-id.appspot.com
應該回傳你剛設的 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
}
]
| 欄位 | 說明 |
|---|---|
origin | 允許的來源網域 |
method | 允許的 HTTP 方法 |
responseHeader | 允許 client 讀取的 response header |
maxAgeSeconds | preflight 結果 cache 時間(秒) |
一個 cors.json 多個 rule可以針對不同 origin 設不同 method:[ { "origin": ["https://prod.com"], "method": ["GET"] }, { "origin": ["http://localhost:3000"], "method": ["GET", "POST"] } ]
替代:用 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();
額外:Cloud Storage 內 metadata 的 CORS 也要
下載連結內含 access token,token 過期就 401。如果你的應用會 cache 連結,記得處理 連結重新生成 的邏輯,否則重啟後讀舊連結會壞。
參考