Remotion LabRemotion Lab
其他CORS 問題

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 失敗的請求:

  1. 開啟瀏覽器開發者工具(F12)
  2. 切換到 Network 分頁
  3. 尋找狀態為紅色或 (blocked:cors) 的請求
  4. 點擊該請求,查看 Response Headers 中是否有 Access-Control-Allow-Origin

小結

情況推薦解決方案
自己控制資源伺服器加入 CORS 標頭
靜態資源(圖片、字體)放入 public/ 目錄使用 staticFile()
外部 API建立代理伺服器
Google Fonts使用 @remotion/google-fonts
S3 資源設定 Bucket CORS 規則
快速開發測試暫時停用 web security(不建議在生產使用)