ブラウザの fetch API を使ってドメインが異なる Web API などに要求を出した時、Web API 側が CORS に対応していない場合のブラウザのエラーメッセージや Fiddler で見た時の要求・応答がどのようになるかを書きます。
検証に使ったのは、先の記事「Web API に CORS 実装 (CORE)」に書いた ASP.NET Core Web API アプリで、Web API の CORS を無効にして、ドメインが異なる MVC アプリから fetch API を使って Web API に要求を出しました。ブラウザは Windows 10 の Chrome 123.0.6312.86 と Edge 123.0.2420.65 です。
ブラウザのエラーメッセージは、ディベロッパーツールの Console タブを開くと見ることができ、Web API 側が CORS 非対応では以下のようになるはずです。赤枠が「単純リクエスト」の場合で、青枠が「プリフライトリクエスト」の場合です。(注: 「単純リクエスト」というのは古い CORS 仕様書の用語で、現在 CORS を定義している Fetch 仕様書 ではその用語を使用していないそうです)
エラーメッセージを以下にコピペしておきます。文章中の 'https://localhost:44371/api/values' が Web API 側で 'https://localhost:44343' がブラウザ側です。
「単純リクエスト」の場合
Access to fetch at 'https://localhost:44371/api/values' from origin 'https://localhost:44343' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
「プリフライトリクエスト」の場合
Access to fetch at 'https://localhost:44371/api/values' from origin 'https://localhost:44343' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
「プリフライトリクエスト」の場合は "Response to preflight request doesn't pass access control check:" という文が追加されています。その文の有無で「プリフライトリクエスト」か否かが分かるはずです。
蛇足ですが、エラーメッセージに含まれる "If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled." を見て mode を no-cors に設定してもほとんどの場合解決にはなりませんので注意してください。詳しくは先の記事「fetch API の mode:"no-cors"」を見てください。
「単純リクエスト」と「プリフライトリクエスト」が必要になる場合の違いについて簡単に書いておきます。「単純リクエスト」になるのは、メソッドが GET, HEAD, POST のいずれかで、かつ、要求ヘッダが「CORS-safelisted request header (CORS セーフリストリクエストヘッダー)」の場合です。それ以外は「プリフライトリクエスト」が必要になります。(詳しくは、MDN のドキュメント「オリジン間リソース共有 (CORS)」を見てください)
例えば、JSON 文字列をコンテンツに含めて POST 送信する場合は要求ヘッダに Content-Type: application/json を含めると思いますが、その場合は「プリフライトリクエスト」が必要になります。
Fiddler で見た時の要求・応答は以下のようになります。CORS の要求側はブラウザの仕事で、プリフライトが必要か否かもブラウザが判断して、下の画像の赤枠で示した CORS に必要な要求を出してくれます。
「単純リクエスト」の場合
ブラウザは Origin を要求ヘッダに含めて送信しますが、応答ヘッダに Access-Control-Allow-Origin が含まれないということででエラーとなっています。
「プリフライトリクエスト」の場合
OPTIONS メソッドを使って CORS に必要なヘッダを要求に含めて出しています。下の画像の赤枠部分を見てください。しかし、応答ヘッダに Access-Control-Allow-Origin が含まれないということでエラーとなっています。
上の「プリフライトリクエスト」の場合の画像で、応答が 405 Method Not Allowed、Allow: GET, POST となっています。これは ASP.NET Core Web API による応答と思われますが、なぜ Method Not Allowed となるのか、GET, POST でないとダメと言われるのかは調べ切れてません。想像ですが、CORS を有効にしないと OPTIONS メソッドが許可されないということではないかと思われます。
参考に、Web API 側が CORS に対応していて、ブラウザ側でデータの取得に成功する場合の要求・応答を Fiddler で見た画像も下に貼っておきます。
「単純リクエスト」の場合
「プリフライトリクエスト」の場合
Web API が CORS に対応しているので「プリフライトリクエスト」の応答ヘッダに Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin が含まれて返ってきます。
ブラウザはそれを見て再度要求を出しデータを取得します。