「HTML/JSから外部API(Reinfolib等)を叩きたいが、APIキーをフロントエンドに書くのは怖いし、CORSエラーで弾かれて動かない…」
この問題を解決するために、Cloudflare Workers を「鍵付きの中継サーバ(プロキシ)」として使い、Cloudflare Pages で安全にサイトを公開する手順をまとめました。
実際に私がハマったポイント(Pagesの404、Consoleの貼り付け制限、CORSの許可リスト設定など)も含めて、「迷わず最後まで完走できる」 手順書として残します。
前回の記事
【建築士×ChatGPT】「1枚のHTML」でツールを作ろうとしたらCORSの闇に落ち、Cloudflare Workersで"裏口"を作って完全勝利した話
この記事のゴール(最終構成)
-
Pages:
https://<PAGES_URL>.pages.dev(HTML公開用) -
Workers:
https://<WORKER_URL>.workers.dev(API中継用) - ブラウザ:Workersだけを呼び出す。APIキーはWorkersが裏で付与する。
- セキュリティ:許可したサイト(Pagesとローカル)以外からのアクセスは拒否する。
1. 準備:Cloudflare Workers(プロキシ)を作る
まず、APIキーを隠し持つ「中継サーバ」を作ります。
1-1. Workers作成
- Cloudflare Dashboard にログインし、左メニュー Workers & Pages をクリック。
- Create application → Workers を選択。
- start with Hello World! を選択。
- 名前を入力(例:
reinfolib-proxy-001)して Deploy。
作成後、表示される Worker URL を控えておきます。
https://reinfolib-proxy-001.<あなたのサブドメイン>.workers.dev
2. APIキーを安全に登録する(Secrets)
コードの中にAPIキーを書くと漏洩します。CloudflareのSecrets機能を使います。
(※Secretsに登録した値は暗号化され、あとから画面で値を見ることができなくなります)
- 作成したWorkerを開く。
- 上部タブ Settings → Variables and Secrets。
- Add をクリック。
- 以下を入力して Save and Deploy。
-
Variable name:
RFL_KEY(コード内で使う変数名) - Value: (あなたのAPIキー / Subscription-Key)
- Type: Secret
-
Variable name:
⚠️注意:保存できない?
Add入力欄に「空の行」が残っているとエラーになります。不要な行はゴミ箱アイコンで消してから保存してください。
3. Workerのコードを作成(CORS対策済み)
3-1. コード編集
Worker画面上部の Edit code をクリックし、worker.js を開きます。
3-2. コードを全置換
以下のコードをコピーし、エディタの中身を全て消して貼り付けてください。
「許可リスト(Allowlist)」 方式を採用しており、指定したURL以外からのアクセスを遮断します。
export default {
async fetch(request, env) {
const u = new URL(request.url);
// ▼▼▼ CORS設定(ここが重要) ▼▼▼
const origin = request.headers.get("Origin") || "";
// 許可するURLリスト(末尾のスラッシュは無しで記述)
const ALLOWED = new Set([
"http://localhost:8787", // ローカル開発用
// "https://<PAGES_URL>.pages.dev" // ★あとでPagesのURLをここに追加
]);
const isAllowed = origin && ALLOWED.has(origin);
// 許可されたOriginなら、そのOriginを返す(Echo方式)
const corsHeaders = isAllowed
? {
"Access-Control-Allow-Origin": origin,
"Vary": "Origin",
"Access-Control-Allow-Methods": "GET,OPTIONS",
"Access-Control-Allow-Headers": "*",
}
: {};
// Preflight (OPTIONS)
if (request.method === "OPTIONS") {
if (!isAllowed) return new Response("Forbidden", { status: 403 });
return new Response(null, { status: 204, headers: corsHeaders });
}
// ▲▲▲ CORS設定ここまで ▲▲▲
const api = u.searchParams.get("api");
// ヘルスチェック(設定確認用)
if (api === "__health") {
return new Response(JSON.stringify({ ok: true, hasKey: Boolean(env.RFL_KEY) }), {
headers: { ...corsHeaders, "content-type": "application/json" },
});
}
if (!api) return new Response("missing api param", { status: 400, headers: corsHeaders });
// 外部APIへ中継(ここでAPIキーを付与)
u.searchParams.delete("api");
const targetUrl = new URL(`https://www.reinfolib.mlit.go.jp/ex-api/external/${api}`);
for (const [k, v] of u.searchParams) targetUrl.searchParams.set(k, v);
const res = await fetch(targetUrl.toString(), {
method: "GET",
headers: {
"Ocp-Apim-Subscription-Key": env.RFL_KEY, // Secretから読み込み
},
});
const body = await res.arrayBuffer();
const headers = new Headers(res.headers);
// レスポンスにもCORSヘッダを付与
for (const [k, v] of Object.entries(corsHeaders)) headers.set(k, v);
return new Response(body, { status: res.status, headers });
},
};
貼り付けたら右上の Deploy を押します。
エラーが出る場合
Uncaught SyntaxError: Unexpected token ']' 等が出る場合は、カッコ [] {} の対応が崩れています。コピー漏れがないか確認してください。
4. 動作確認(F12コンソールの儀式)
ブラウザだけでWorkerが生きているか確認します。
- Chromeで新しいタブを開く(何もないページでOK)。
- F12キー → Console タブを開く。
4-1. 貼り付け許可(allow pasting)
Consoleにコードを貼ろうとすると、セキュリティ警告が出ることがあります。その場合は手動で以下を入力してEnter。
allow pasting
4-2. ヘルスチェック実行
以下のコードをConsoleに貼り付けて実行します。(URLは自分のWorkerのものに書き換えてください)
// テスト用コード
fetch("https://reinfolib-proxy-001.<あなたのサブドメイン>.workers.dev/?api=__health")
.then(r => r.json())
.then(console.log)
.catch(console.error);
成功時の表示:
{ok: true, hasKey: true}
5. HTMLをPagesで公開する
5-1. Pagesプロジェクト作成
- Cloudflare Dashboard → Workers & Pages。
- Create application → Pages → Upload assets。
- プロジェクト名(例:
<あなたのサブドメイン>)を入力して Create project。
5-2. アップロード(404の罠に注意)
「Upload your project assets」で、HTMLが入ったフォルダをドラッグ&ドロップします。
⚠️ 最重要:404エラーを防ぐために
アップロードするフォルダの**一番上(ルート直下)**にindex.htmlがある状態でアップしてください。
フォルダ > フォルダ > index.htmlのように深い階層になっていると、公開後に 404 Not Found になります。
Deploy site を押し、成功したらURL(例:https://<あなたのサブドメイン>.pages.dev)を控えます。
6. 仕上げ:Workerの許可リストを更新
このままだと、CORS制限によりPagesからAPIを叩けません。Workerに「PagesからのアクセスはOKだよ」と教えてあげます。
- Workerの Edit code に戻る。
-
ALLOWEDのリストに、PagesのURLを追加する。
// 許可するURLリスト
const ALLOWED = new Set([
"http://localhost:8787", // ローカル確認用
"https://<あなたのサブドメイン>.pages.dev" // ★追加したPagesのURL(末尾スラッシュなし)
]);
- Deploy を押す。
最終確認方法
Pagesの公開URLを開き、F12 → Console で以下を入力します。
location.origin
表示されたURL(例:https://<あなたのサブドメイン>.pages.dev)が、Workerのリストと完全に一致していれば成功です!
補足:ローカル開発の注意点(file://禁止)
PC上のHTMLファイルをダブルクリックで開くと、URLが file://C:/Users/... になります。
この状態だと Origin が null になりやすく、CORSエラーの原因になります。
ローカルで動かす場合は、必ずローカルサーバを立ててください。
(WindowsならHTMLのあるフォルダでPowerShellを開き、以下を実行するのが最短です)
py -m http.server 8787
その後、Chromeで http://localhost:8787 にアクセスすればOKです。
👉 【建築士×GIS】Google Maps上で「雨水の流下経路」を1クリック追跡する“HTML1枚”ツールを作った(国土地理院 標高×道路中心線×Cloudflare Pages)
以上で、「セキュアで、APIキーを隠蔽し、CORSも回避できる」 環境の完成です。






