0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Day7 — CORSを図で理解:なぜ通信がブロックされるのか?どう回避するのか?

Last updated at Posted at 2025-12-07

はじめに

React や Next.js から API を叩いたとき、
こんなエラーを見たことはありませんか?

Access to fetch at 'http://localhost:8000/api/users'
from origin 'http://localhost:3000' has been blocked by CORS policy

この瞬間、誰もがこう思います。

「え?通信できてるはずなのに、なぜかブロックされる…」

その正体が CORS(コルス) です。

この記事では、

・CORS とは何なのか
・なぜブラウザだけがブロックするのか
・なぜ Postman だと通るのか
・Laravel での正しい解決方法
・よくある “やらかしパターン”

まで、実務でできるだけ詰まらないレベルで解説 します。

今日のゴール

・CORS が「何をしている仕組み」なのかが説明できる

・なぜ React → Laravel でだけエラーが出るのか分かる

・Preflight Request(OPTIONS)の正体が分かる

・Laravel で CORS を正しく解除できる

まず結論:CORS は「ブラウザのセキュリティ機能」

CORS とは、

Cross-Origin Resource Sharing(オリジンをまたぐ通信の制御)
ブラウザが勝手にやっているセキュリティチェック

です。

つまり、

❌ サーバが通信を拒否している
✅ ブラウザが通信を止めている

これが最大の勘違いポイントです。

「オリジン」とは何か?

オリジンは次の3つの組み合わせで決まります。

① プロトコル(http / https)
② ドメイン(localhost / example.com)
③ ポート番号(3000 / 8000)

たとえば:

URL オリジン
http://localhost:3000 A
http://localhost:8000 B

この2つは
同じ localhost でも「別オリジン」扱い になります。

なぜ CORS が必要なのか?

もし CORS がなかったらどうなるか?

あなたが悪意あるサイトにアクセスした瞬間、

・Twitter の投稿を勝手に削除

・銀行の送金APIを勝手に実行

・管理画面の設定を勝手に変更

これが ブラウザから自由に実行できてしまいます。

それを防ぐ最後の砦が CORS です。

通信の流れを超シンプルに図解

【React : localhost:3000】
        ↓
  APIリクエスト
        ↓
【Laravel : localhost:8000】
        ↓
  レスポンス
        ↓
【ブラウザ】
  「この通信、許可されてる?」
        ↓
  CORSヘッダーが無い → ❌ ブロック

ブロックしているのは “サーバ” ではなく “ブラウザ”

なぜ Postman や curl では CORS が出ないのか?

答えはシンプルです。

Postman や curl は “ブラウザではない” から

CORS は
ブラウザ専用のセキュリティ機構
✅ サーバ間通信・CLI ツールには存在しません

だから

・Postman → 通る

・React → ブロックされる

という現象が起きます。

CORS を許可するために必要なヘッダー

サーバが以下のようなヘッダーを返すと、ブラウザは通信を許可します。

Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type

つまり、

「このオリジンからの通信はOKですよ」
とサーバが宣言する必要があります。

Laravel で CORS を正しく設定する

Laravel では標準で
config/cors.php が用意されています。

設定例(開発環境)

return [
    'paths' => ['api/*'],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['http://localhost:3000'],
    'allowed_headers' => ['*'],
    'supports_credentials' => true,
];

これで、

✅ React(3000) → Laravel(8000)
✅ API 通信が正常に通る

ようになります。

Preflight Request(OPTIONS)とは?

PUT / DELETE / Authorization ヘッダー付き通信のとき、
ブラウザは いきなり本通信をしません。

代わりにまずこれを送ります。

OPTIONS /api/users

これを Preflight Request(事前確認) と言います。

ブラウザはここで、

✅ 「この通信、本当に送っていい?」
をサーバに確認してから、

OK  本通信
NG  CORSエラー

という動きをします。

初心者がハマりやすい CORS 事故パターン

全オリジン許可を本番に入れる

'allowed_origins' => ['*'],

✅ 開発ではOK
❌ 本番では セキュリティ事故の原因

Authorization ヘッダーを許可していない

Access-Control-Allow-Headers: *

が無いと

✅ トークンを送った瞬間に CORS エラーになります。

Cookie 認証で supports_credentials を false にしている

'supports_credentials' => false

→ Cookie が送られず ログインできない地獄 に入ります。

今日のまとめ

・CORS は「ブラウザが勝手にやっているセキュリティ機構」

・サーバが拒否しているのではなく、ブラウザがブロックしている

・同一オリジンは「プロトコル・ドメイン・ポート」の3点セット

・Postman では CORS は発生しない

・Laravel では config/cors.php がすべて

・OPTIONS(Preflight)を理解すると CORS は怖くなくなる

次回 Day8 は…

「REST APIとは?RESTfulなURL設計を本気で考えてみる」
「それっぽいAPI」から
「ちゃんと設計されたAPI」にレベルアップする回です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?