3秒でわかる
別のオリジンへのブラウザからの通信を、サーバーの許可があるときだけ通す仕組み。APIを他サイトのJavaScriptに安全に開放するために設定します。
30秒図解
もう少し詳しく
どういうものか
CORS は Cross-Origin Resource Sharing の略で、あるオリジンで開いたページの JavaScript が別のオリジンへ通信することを、サーバーの許可がある場合に限って認める仕組みです。オリジンはスキーム、ホスト、ポートの三点セットで、どれか一つでも違えば別のオリジンとして扱われます。ブラウザは既定でこの越境を止めており、サーバーが返す Access-Control-Allow-Origin などのヘッダーを見て、応答をページに渡してよいかを判断します。
重要なのは、止めているのがブラウザだという点です。サーバーにはリクエストが届いて処理も走っていることが多く、ブラウザが応答を読ませないだけです。
なぜ必要か
もし制限が無ければ、悪意のあるサイトを開いただけで、そこの JavaScript が利用者のログイン済み Cookie を伴って社内システムへリクエストを送り、結果を読み取れてしまいます。同一オリジンポリシーはこれを防ぐ土台で、CORS は「読ませてよい相手をサーバーが明示的に選ぶ」ための例外の作り方です。
具体例
import express from "express";
const app = express();
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "https://app.example.com");
res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
res.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
res.setHeader("Access-Control-Allow-Credentials", "true");
if (req.method === "OPTIONS") return res.sendStatus(204);
next();
});Content-Type が application/json の POST や、独自ヘッダーを付けたリクエストでは、本番のリクエストの前にブラウザが OPTIONS で許可を問い合わせます。これがプリフライトで、上の分岐はそれに応えるためのものです。
つまずきやすいところ
Cookie や認証情報を伴う通信では、Access-Control-Allow-Origin にワイルドカードの * を使えません。許可するオリジンを具体的に書く必要があり、* のままだとブラウザが応答を拒みます。
もう一つは、原因の取り違えです。CORS のエラーが出ている場面でサーバーのログを見ると、リクエストは 200 で成功していることがよくあります。直す場所はフロントエンドではなくサーバーのヘッダー設定です。開発中だけの回避としてブラウザの安全機能を切る手もありますが、本番と挙動が変わるため、早い段階でサーバー側の設定を入れる方が結果的に早く終わります。