CORS 問題
在 Remotion 開發與渲染中遇到的 CORS 問題說明與解決方案。
CORS 問題
跨來源資源共用(Cross-Origin Resource Sharing,CORS) 是瀏覽器的安全機制,限制網頁載入來自不同來源的資源。在 Remotion 開發和渲染過程中,CORS 問題是常見的障礙之一。
什麼情況下會遇到 CORS?
在以下情況中,Remotion 可能遇到 CORS 問題:
- 在 Remotion Studio 中預覽時,嘗試載入來自外部 CDN 的圖片或字體。
- 在渲染時,使用
<Img>或<Video>元件載入外部資源。 - 使用
fetch()在元件內請求外部 API 資料。 - 使用
@remotion/media-utils中的函式分析外部媒體檔案。
常見的錯誤訊息
Access to fetch at 'https://api.example.com/data' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
解決方案
方案一:讓資源伺服器加入 CORS 標頭
最根本的解決方案是讓提供資源的伺服器加入正確的 CORS 標頭:
Access-Control-Allow-Origin: *
# 或指定特定來源
Access-Control-Allow-Origin: https://your-domain.com若你控制資源伺服器,這是最推薦的做法。
方案二:使用代理伺服器
若你無法控制外部資源的伺服器,可以設定代理:
// Next.js API Route 作為代理
// pages/api/proxy.ts
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { url } = req.query;
if (typeof url !== "string") {
return res.status(400).json({ error: "缺少 url 參數" });
}
const response = await fetch(url);
const buffer = await response.arrayBuffer();
res.setHeader("Content-Type", response.headers.get("Content-Type") || "");
res.setHeader("Access-Control-Allow-Origin", "*");
res.send(Buffer.from(buffer));
}在 Remotion 元件中使用代理:
const proxyUrl = `/api/proxy?url=${encodeURIComponent(
"https://external-cdn.com/image.png"
)}`;
<Img src={proxyUrl} />;方案三:將資源放入 public/ 目錄
對於固定的靜態資源(圖片、字體、影片片段),最簡單的做法是直接放入 Remotion 專案的 public/ 目錄,並使用 staticFile() 引用:
import { Img, staticFile } from "remotion";
// 資源放在 public/images/logo.png
<Img src={staticFile("images/logo.png")} />;方案四:停用 CORS 檢查(僅開發環境)
在 Remotion Studio 中,可以透過 Chromium 旗標暫時停用 CORS:
// remotion.config.ts
import { Config } from "@remotion/cli/config";
Config.setChromiumDisableWebSecurity(true); // 僅開發環境使用!或透過 CLI:
npx remotion studio --disable-web-security警告:請勿在生產渲染環境中使用此設定,這會帶來安全風險。
特定場景的處理
Google Fonts
Google Fonts 的 CSS 端點支援 CORS,可以直接在 Remotion 中使用:
import { useEffect } from "react";
import { delayRender, continueRender } from "remotion";
const handle = delayRender("載入字體");
// 在 HTML head 中加入字體連結
const link = document.createElement("link");
link.rel = "stylesheet";
link.href =
"https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap";
link.crossOrigin = "anonymous";
document.head.appendChild(link);
link.onload = () => continueRender(handle);更推薦使用 @remotion/google-fonts 套件:
import { loadFont } from "@remotion/google-fonts/Roboto";
const { fontFamily, waitUntilDone } = loadFont("normal", {
weights: ["400", "700"],
});
const handle = delayRender("載入字體");
waitUntilDone().then(() => continueRender(handle));AWS S3 資源
若媒體資源放在 S3 上,需要在 S3 Bucket 設定 CORS 規則:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET"],
"AllowedOrigins": ["*"],
"ExposeHeaders": []
}
]Cloudflare R2 / CDN 資源
在 Cloudflare 中,可以透過 Workers 加入 CORS 標頭,或在 CDN 設定中啟用 CORS。
在渲染時避免 CORS 問題
伺服器端渲染(透過 renderMedia())是透過 Chromium 執行的,Chromium 同樣會檢查 CORS。若要在渲染時避免 CORS 問題:
await renderMedia({
composition,
serveUrl,
codec: "h264",
outputLocation: "out/video.mp4",
chromiumOptions: {
// 僅在確認安全的情況下使用
disableWebSecurity: false,
},
});最好的做法仍是確保所有資源都正確設定 CORS 標頭,而非停用安全檢查。
診斷 CORS 問題
在開發者工具的 Network 分頁中,可以識別 CORS 失敗的請求:
- 開啟瀏覽器開發者工具(F12)
- 切換到 Network 分頁
- 尋找狀態為紅色或
(blocked:cors)的請求 - 點擊該請求,查看 Response Headers 中是否有
Access-Control-Allow-Origin
小結
| 情況 | 推薦解決方案 |
|---|---|
| 自己控制資源伺服器 | 加入 CORS 標頭 |
| 靜態資源(圖片、字體) | 放入 public/ 目錄使用 staticFile() |
| 外部 API | 建立代理伺服器 |
| Google Fonts | 使用 @remotion/google-fonts |
| S3 資源 | 設定 Bucket CORS 規則 |
| 快速開發測試 | 暫時停用 web security(不建議在生產使用) |