CDNと静的アセットのCORS設定
CDNからフォント、画像、スクリプトを配信するためのCORSヘッダー設定。S3、CloudFront、Cloudflare、フォント読み込みのよくある問題を解説します。
Common Issues
詳細な説明
CDNアセットにCORSが必要な理由
https://app.example.comのWebページがhttps://cdn.example.comからフォントを読み込む場合、ブラウザはこれをクロスオリジンリクエストとして扱います。CORSヘッダーなしでは、フォントがブロックされ(特にFirefox)、FOUT(Flash of Unstyled Text)や文字化けが発生します。
CORSが必要なリソース
| リソース | CORSが必要? |
|---|---|
フォント(@font-face) |
はい — 常にクロスオリジンブロック |
<canvas>内の画像 |
はい — drawImageでcanvasが汚染される |
| JavaScriptモジュール | はい — <script type="module">はCORSを使用 |
通常の<script> |
いいえ — "no-cors"モードで読み込み |
通常の<img> |
いいえ — canvas経由で読み取る場合を除く |
| CSSスタイルシート | いいえ — fetch()を使用する場合を除く |
AWS S3 + CloudFront
S3バケットCORS設定:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedOrigins": ["*"],
"ExposeHeaders": ["Content-Length", "Content-Type", "ETag"],
"MaxAgeSeconds": 86400
}
]
CloudFront: Origin Request PolicyにOriginを追加し、Response Headers PolicyにAccess-Control-Allow-Originを追加します。
Cloudflare
Cloudflare WorkersでCORSヘッダーを追加:
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const response = await fetch(request);
const newHeaders = new Headers(response.headers);
newHeaders.set("Access-Control-Allow-Origin", "*");
newHeaders.set("Access-Control-Max-Age", "86400");
return new Response(response.body, { ...response, headers: newHeaders });
}
Nginx静的ファイル向け
location ~* \.(woff2?|ttf|eot|otf|svg|png|jpg|webp)$ {
add_header Access-Control-Allow-Origin "*" always;
add_header Access-Control-Max-Age 86400 always;
add_header Cache-Control "public, max-age=31536000, immutable";
}
フォント固有のヒント
フォントがChromeでは読み込まれるがFirefoxではない場合、ほぼ確実にCORSの問題です。Firefoxは@font-faceリソースのCORS強制がより厳格です。
ユースケース
WebアプリケーションがCDNサブドメインからカスタムWebフォントを読み込んでいます。ChromeではフォントがレンダリングされますがFirefoxでは表示されません。修正はフォントファイルに対するCDNのレスポンスヘッダーにAccess-Control-Allow-Origin: *を追加することです。