Azure FunctionsのHTTPエンドポイントをcurlやPowerShellなどから呼ぶと成功するのに、Web画面から実行したときだけCORSエラーになる場合は、まずAzure Functions側のCORS許可元を確認します。
ポイントは、CORSで登録するのがAzure FunctionsのURLではなく、Functionsを呼び出しているWebサイト側のオリジンであることです。Azure FunctionsではCORSの許可元が関数アプリ単位で管理されるため、必要なWebサイトのオリジンだけを登録します。認証、Function Key、アクセス権限などとは別の設定として切り分けることが重要です。
この記事では、要求元の確認から現在のCORS設定の確認、許可元の追加、認証エラーとの切り分けまで、Azure CLIを使って順番に整理します。
Azure Functionsをブラウザーから呼ぶとCORSエラーになる理由
Azure Functionsでは、別のWebサイトからHTTPトリガーのエンドポイントへアクセスするためのCORS設定を関数アプリ単位で管理できます。
Microsoft Learnでも、CORSルールはFunction App単位で定義され、アクセスを許可するWebアプリのドメインを個別に登録することが推奨されています。
そのため、次のような状態は矛盾ではありません。
| 呼び出し方法 | 結果 |
|---|---|
| コマンドからFunctionsへアクセス | 成功 |
| WebアプリからFunctionsへアクセス | CORSエラー |
| Function Keyなどを付けたWebアクセス | CORSエラーのまま |
コマンドからHTTPエンドポイントを呼び出せたとしても、それだけではWebサイトのオリジンがCORSで許可されていることを確認したことにはなりません。
特に注意したいのは、CORSと認証を混同しないことです。
Azure FunctionsにはFunction KeyやApp Service Authenticationなど、HTTPエンドポイントを保護する別の仕組みがあります。CORSはそれらの代わりではありません。
最初に確認するのは呼び出し先ではなく要求元のオリジン
CORSを設定するときに最も間違えやすいのが、「どのURLを登録するのか」です。
たとえば、次の構成だったとします。
Webサイト
https://example.com
↓ JavaScriptから呼び出す
Azure Functions
https://sample-function.azurewebsites.net/api/example
CORSの許可元として確認するのは、Functions側の
https://sample-function.azurewebsites.net
ではなく、Webサイト側の
https://example.com
です。
オリジンはスキーム・ホスト・ポートまで確認する
見た目が似ていても、次のようなURLは同じものとして扱わない前提で確認します。
https://example.com
http://example.com
https://www.example.com
https://app.example.com
http://localhost:5173
https://example.com:8443
開発環境では特に、localhostのポート番号を見落としやすくなります。
たとえばWebアプリを
http://localhost:5173
で起動している場合、必要な許可元もこのオリジンです。
Azure CLIのCORSコマンドでも、許可元の例としてポート番号を含む形式が使用されています。
ブラウザーの開発者ツールなどで、実際にWebページを開いているURLを確認してから設定すると間違いが減ります。
Azure Functionsの現在のCORS設定を確認する
要求元が分かったら、すぐに追加するのではなく、最初に現在の設定を確認します。
Azure CLIでは次のコマンドを使用できます。
az functionapp cors show -g RG -n APP
RGにはリソースグループ名、APPにはFunction App名を指定します。
たとえば説明用に次の名前だったとします。
リソースグループ: example-rg
Function App: example-function
この場合は次の形になります。
az functionapp cors show -g example-rg -n example-function
az functionapp cors showは、Function Appに設定されている許可元を確認するためのAzure CLIコマンドです。
ここで確認したいのは、ブラウザーからアクセスしているWebサイトのオリジンが既に登録されているかどうかです。
たとえば要求元が
https://example.com
なら、そのオリジンが許可元に含まれているか確認します。
必要なオリジンだけCORSに追加する
必要なオリジンが登録されていなければ、az functionapp cors addで追加できます。
基本形は次のとおりです。
az functionapp cors add -g RG -n APP --allowed-origins https://example.com
実際にはRG、APP、https://example.comを自分の環境に置き換えます。
説明用の例では次のようになります。
az functionapp cors add \
-g example-rg \
-n example-function \
--allowed-origins https://example.com
Azure CLIでは--allowed-originsを使って、クロスオリジン要求を許可するオリジンを指定できます。
設定後はもう一度確認しておくと安全です。
az functionapp cors show -g example-rg -n example-function
ここまでできたら、ブラウザーから同じ操作を再実行します。
CORSはFunction App単位なので影響範囲に注意する
Azure FunctionsのCORS設定で重要なのが、関数単位ではなくFunction App単位で設定されることです。
たとえば一つのFunction Appに、
/api/users
/api/orders
/api/report
という複数のHTTPトリガーがある場合、「/api/usersだけのためにCORSを追加した」という感覚で設定しないほうが安全です。
CORSの許可元リストはFunction Appレベルの設定として扱われます。
実務では、
- どのWebサイトからアクセスさせるのか
- そのFunction AppにはほかにどのHTTPエンドポイントがあるのか
- そのオリジンをFunction App全体として許可して問題ないか
まで確認してから追加すると、不要な許可を残しにくくなります。
ワイルドカード「*」で恒久対応しない
Azure CLIでは、許可元として*を指定することもできます。
しかし、Microsoft Learnでは、すべてのサイトを許可するワイルドカードではなく、アクセスを必要とするWebアプリのドメインを個別に登録するよう案内されています。
したがって、本番環境で
*
を恒久的な解決策として設定するのは避けます。
たとえば、
https://example.com
からしか利用しないのであれば、そのオリジンだけを許可します。
開発環境と本番環境の両方が必要なら、それぞれ必要性を確認したうえで登録します。
http://localhost:5173
https://example.com
「CORSエラーが消えればよい」という理由だけで許可範囲を広げないことが重要です。
CORSが直った後に401や403が出る場合は別問題
CORS設定を修正した後、エラーが
401 Unauthorized
403 Forbidden
などに変わることがあります。
この場合は、CORSだけを見るのではなく認証・認可側へ切り分けます。
Azure Functionsでは、HTTPエンドポイントの保護としてFunction KeyやApp Service Authentication/Authorizationなどを利用できます。Microsoft Learnでも、CORSとは別にHTTPエンドポイントのアクセスキーや認証について説明されています。
切り分けの考え方は次のようになります。
| 状況 | 主に確認する場所 |
|---|---|
| ブラウザーでCORSエラー | CORSの許可元 |
| 401になる | 認証情報や認証設定 |
| 403になる | 認可、アクセス制限、アプリ側の拒否条件など |
| Function Keyが必要 | HTTPトリガーのアクセスレベルやキー |
| 特定ネットワークからしか接続できない | App Serviceのアクセス制限など |
重要なのは、CORSを認証機能として扱わないことです。
CORSで
https://example.com
を許可したからといって、そのWebサイトの利用者本人が認証されたことにはなりません。
反対に、正しいAPIキーや認証情報を持っていても、ブラウザーの要求元がCORSで許可されていなければ、CORS側の問題は別途解決する必要があります。
CORSとアクセス制限も別物として考える
Azure Functionsには、CORS以外にもApp Serviceのアクセス制限などがあります。
Microsoft Learnでは、アクセス制限について、許可・拒否ルールを使ってアプリへのトラフィックを制御する仕組みとして説明しています。
つまり、
CORS
と
ネットワークやIPなどによるアクセス制御
は目的が異なります。
「CORSを設定したから、許可していないコマンドラインクライアントからAPIを呼べなくなる」と考えるのは適切ではありません。
HTTPエンドポイント自体を保護したい場合は、認証、アクセスキー、ネットワーク制限などを含めて別途設計します。
不要になったCORS許可元を削除する
開発終了後のlocalhostや、廃止したWebサイトのオリジンを残し続ける必要はありません。
不要な許可元はaz functionapp cors removeで削除できます。
az functionapp cors remove \
-g RG \
-n APP \
--allowed-origins https://example.com
説明用の例では次のようになります。
az functionapp cors remove \
-g example-rg \
-n example-function \
--allowed-origins http://localhost:5173
Azure CLIではcors removeによる許可元の削除がサポートされています。
削除後は再度、
az functionapp cors show -g example-rg -n example-function
で確認しておくと確実です。
デプロイスロットを使っている場合は対象を間違えない
Azure Functionsでデプロイスロットを利用している場合は、CORSを変更する対象にも注意します。
az functionapp corsのadd、show、removeには--slotオプションがあります。--slotを指定しない場合はProductionスロットが対象になります。
たとえばstagingスロットを確認するなら、次のような形です。
az functionapp cors show \
-g RG \
-n APP \
--slot staging
許可元を追加する場合も同様です。
az functionapp cors add \
-g RG \
-n APP \
--slot staging \
--allowed-origins https://staging.example.com
ステージング環境でCORSエラーが出ているのにProduction側だけ変更してしまうと、原因が解消しません。
スロットを利用している環境では、CORS設定を変更する前に「今ブラウザーがアクセスしているエンドポイントがどのスロットなのか」を確認します。
Web画面だけCORSで失敗するときの確認順序
原因を素早く絞り込むには、次の順序で確認すると分かりやすくなります。
要求元を確認する
ブラウザーで開いているWebサイトのオリジンを確認します。
https://example.com
開発中なら、ポート番号まで確認します。
http://localhost:5173
現在のCORS設定を確認する
az functionapp cors show -g RG -n APP
スロットを使っている場合は対象スロットも確認します。
必要なオリジンだけ追加する
az functionapp cors add \
-g RG \
-n APP \
--allowed-origins https://example.com
*で広く許可するのではなく、実際に必要な要求元を登録します。
ブラウザーから再実行する
CORSエラーが消えたか確認します。
ここで401や403など別のエラーになった場合は、CORS設定を追加し続けるのではなく、認証・認可・アクセス制御へ調査対象を移します。
不要な許可元を削除する
az functionapp cors remove \
-g RG \
-n APP \
--allowed-origins https://old.example.com
一時的な開発環境や廃止済みサイトのオリジンを残さないようにします。
まとめ
Azure FunctionsのHTTPエンドポイントがコマンドからは呼べるのに、Web画面からだけCORSで拒否される場合は、まずWebサイト側の要求元オリジンとFunction AppのCORS設定を照合します。
確認すべき流れはシンプルです。
- ブラウザーの要求元オリジンを確認する
az functionapp cors showで現在の設定を見るaz functionapp cors addで必要なオリジンだけ追加する- ブラウザーから再実行する
- 401・403などが残れば認証や権限を別に調べる
- 不要な許可元は
az functionapp cors removeで削除する
CORSはFunction App単位で設定され、認証やAPIキー、ネットワークアクセス制御とは役割が異なります。
「コマンドでは成功するからFunctions側は問題ない」と判断するのではなく、要求元 → 現在のCORS設定 → 必要な許可元 → 認証・権限の順番で切り分けると、原因を追いやすくなります。

コメント