JSから異なるサーバーのAPIへ送信 CORS(Cross-Origin Resource Sharing)

has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource

LaravelのJSから異なるサーバー(異なるドメイン)のAPIへAjaxで送信したとき、以上のようなエラーが起きた。

CORSポリシー

セキュリティ向上のため、CORSポリシーは、異なるオリジン(ドメイン、プロトコル、ポート番号)からのリクエストを制御している。

Laravelのクライアント側のドメインと違うドメインにあるAPIに直接送信はするためには、送信先のAPIでCORSの設定をしていないといけない。

Laravelのコントローラーからはサーバー側での処理になるので、ブラウザの同一オリジンポリシー(Cross-Origin Policy)の影響を受けない。

対策

解決策として送り先のAPIに以下の設定を書く。

header("Access-Control-Allow-Origin: http://web.local");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Authorization");

最初の Access-Control-Allow-Origin は、送信元のサーバーのドメインになる。*を書けば、すべての送信元からのリクエストを許可してしまうのでセキュリティ的によくない。

そもそも、クライアント側から直接送信するのもよくないが。。。

参考

https://qiita.com/daaaayoshi/items/887dd6149f6a8a00d682

プリフライト(preflight)リクエストは、クロスオリジンリクエストを行う際にブラウザが行う予備的なリクエストです。クロスオリジンリクエストとは、異なるオリジン(ドメイン、ポート、プロトコルの組み合わせ)にあるリソースへのリクエストのことです。

クロスオリジンリクエストが安全であるかどうかを判断するために、ブラウザは最初にOPTIONSメソッドを使用してプリフライトリクエストを送信します。このプリフライトリクエストには、実際のリクエストに含まれるであろうHTTPメソッドやヘッダーなどの情報が含まれます。サーバーはこのプリフライトリクエストに対して適切なレスポンスを返し、リクエストを許可するかどうかを決定します。

プリフライトリクエストに対するサーバーのレスポンスは、Access-Control-Allow-* ヘッダーを含む必要があります。これらのヘッダーは、ブラウザに対して許可を与えるための指示を含みます。具体的には、Access-Control-Allow-Origin ヘッダーは、クロスオリジンリクエストを行う元のオリジンに対してアクセスを許可するかどうかを指定します。

プリフライトリクエストが成功し、サーバーからのレスポンスが許可を示す場合、ブラウザは実際のリクエストを送信します。この際、ブラウザは実際のリクエストに含まれる情報をもとに、サーバーに対してリソースを要求します。

つまり、クロスオリジンリクエストを行う際には、ブラウザがプリフライトリクエストを送信し、サーバーが適切なレスポンスを返すことで、リクエストの許可を確認します。

ChatGPT