@irebasunglass213

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

リクエストをLaravelで受け取れない(CORSエラー)

解決したいこと

フロント側から受け取ったオブジェクトデータをLaravel側のpublicディレクトリの中にあるJsonファイルに書き込みたいと思ってます。
しかしCORSエラーに悩まされております。Laravel10を使用しているのでミドルウェアの追加はいらないというとこを知りましたが。 ほかの方法及び原因が見当たりません。

発生している問題・エラー

Access to XMLHttpRequest at 'http://localhost/api/players' from origin 'http://localhost:3000' 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.

または、問題・エラーが起きている画像をここにドラッグアンドドロップ

フロント側(React)

const headers = {"Content-Type": "application/json","Access-Control-Allow-Origin": "http://localhost:3000"};

        const instance = axios.create({
         baseURL : 'http://localhost',
         headers:headers
        });

        try {
          await instance.post('http://localhost:/api/players ',reobj); //reobjというオブジェクトデータ
        } catch (error) {
          console.log(error)
        }

バックエンド側(Laravel)のコントローラー


class PlayersController extends Controller
{

    /**
     * プレイヤー一覧を表示する
     * 
     * @return view
     */


     public function showPlayers() 
     {
         
     }


    public function savePlayers(Request $request) 
    {   
        $playersData = $request->all();
        $jsonData = json_encode($playersData);
        file_put_contents('players_list.json', $jsonData); //今回行いたいLaravel側の処理
    }

}


api.phpでルーティングしましたのルーティング

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Route::post('/players', [PlayersController::class, 'savePlayers']); //今回のコントローラー

cors.phpは以下の設定です。


return [

    /*
    |--------------------------------------------------------------------------
    | Cross-Origin Resource Sharing (CORS) Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure your settings for cross-origin resource sharing
    | or "CORS". This determines what cross-origin operations may execute
    | in web browsers. You are free to adjust these settings as needed.
    |
    | To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
    |
    */

    'paths' => ['api/*', 'sanctum/csrf-cookie', 'players*'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['http://localhost:3000'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => false,

];

ルートの定義は仕方も下記のページを見て行いました。

私的にはCORS対策として不備があるようには見えないのですがエラーが一向に改選されず
悩んでおります。上記の提示しているところでもし不備があれば教えていただけますでしょうか?
よろしくお願いいたします。

0 likes

2Answer

Fiddler などのキャプチャツールを使って要求・応答ヘッダがどうなっているか調べてください。ヘッダに "Content-Type": "application/json" があるのでシンプルなリクエストにならず、プリフライトリクエストが出ます。正しく設定されていれば以下のようになるはずです。

option.jpg

0Like

Comments

  1. 回答ありがとうございました。
    Content-Type": "application/jsonの記述は削除いたしました。
    スクリーンショット 2023-10-23 160933.png
    ヘッダーの情報が画像の通りに出ます。

  2. Content-Type": "application/jsonの記述は削除いたしました。

    質問のコード instance.post('http://localhost:/api/players ',reobj) を見ると、json 文字列を POST しているように思えますが、そうであれば、それは消してはいけないはずです。

    あと、質問者さんが貼った Fiddler の画像を見ると、要求ヘッダの Access-Control-Request-Headers: access-control-allow-origin が変です。

    質問のコード、

    const headers = {"Content-Type": "application/json","Access-Control-Allow-Origin": "http://localhost:3000"};
    

    の影響のようですね。

    Access-Control-Request-Headers はブラウザが自動的に要求ヘッダに設定してサーバーに送信するもので、プログラマがコードを書いて設定するものではないです。

    Access-Control-Allow-Origin は要求を受けてサーバーが自動的に設定するもので、これもプログラマがコードを書いて設定するものではないです。

    要求ヘッダに Content-Type: application/json が含まれると、ブラウザが自動的に要求ヘッダに Access-Control-Request-Headers: content-type を含めて送信します。

    私の回答に貼った画像にある要求ヘッダを見てください。

    サーバーが CORS に対応していれば、プリフライトリクエストに対しては 204 No Content が返ってきて、応答ヘッダには Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers が含まれます。

    私の画像の応答ヘッダではそうなっているのが分かりますか?

    ブラウザはそれを見てサーバーに POST 要求を出して応答を取得します。私の回答に貼った画像の左側のウィンドウの #2 がそれです。

    そのあたりのプロセスは以下の記事に詳しく書いてあるので一読して基本的な知識を得てください。でないと話が通じないと思いますので。

    オリジン間リソース共有 (CORS)
    https://developer.mozilla.org/ja/docs/Web/HTTP/CORS

    質問者さんが貼った Fiddler 画像を見ると、要求の HTTP 動詞は OPTIONS となっているので CORS のプリフライトリクエストが出ています。(同じ localhost でもポートが違えばクロスドメインとみなされます)

    しかし、サーバーからの応答はそれに対応してなくて、応答は 204 ではなくて 200 ですし、応答ヘッダに Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers が含まれません。

    ということで、たぶんサーバー側の CORS 対応の設定に問題があるようです。

  3. ありがとうございます。Access-Control-Request-Headersの値はcontent-typeになりました。 
    レスポンスがないためLaravel側の設定を見直します。

  4. cors.php で paths とか allowed_origins に制限をかけているように見えますが、とりあえず制限するのは止めて試してみたらどうなりますか?

  5. ありがとうございます。Cora.phpのpathsとallowed_originsをワイルドカードに変えましたが解消できませんでした。

  6. そうですか、とすると Laravel の知識がない自分はお役に立てそうもありません。すみませんが、他の方の回答をお待ちください。

Jsonに対する書き込みの前に、そもそもAPIにアクセスできないという状況ですので、それに絞ったほうがノイズが減って考えやすいと思います。
具体的には、単純なリクエストが出来てから先に進むイメージです。

route/api.php
// 単純なレスポンスを返すルートを作成して、アクセスできることを確認する
Route::get('/check', function() { return 'Hello World'; });

LaravelのCORS設定について、デフォルトの設定はすべて許可されている状態だったと思いますが、その状態では接続できなかったのでしょうか?
Access-Control-Allow-Originはアスタリクス * を指定することで全て許可されます。

config/cors.php
-    'allowed_origins' => ['http://localhost:3000'],
+    'allowed_origins' => ['*'],

その他気になるところ

  • ルートの状態 php artisan route:list
  • CORS設定の変更は反映されているか(例えば古い設定がキャッシュされていないか)
0Like

Comments

  1. 回答ありがとうございました。
    Route::get('/check', function() { return 'Hello World'; });
    上記をルーティングしフロント側からアクセスしましたが同じエラーが消えません。
    config/cors.phpをデフォルトの設定に戻しましたが同じ症状でした。
    キャッシュについては設定とアプリケーションのキャッシュの削除をを試しましたが
    同じエラー続く状態でした

  2. 確認ありがとうございます。
    おそらくいろいろ試せされていていると思っているので現状を整理したいのですが、次の状態でも同じエラーが継続している状態でしょうか?

    • LaravelのCORS設定はデフォルト
    • シンプルなAPIへのGETリクエスト
    • フロント側のヘッダー指定はされていない

    また、WebサーバーでCORSの設定がされている、ということはないでしょうか?
    CORS設定はconfig('cors.allowed_origins')などで反映されていることが確認できていますか?


    私の環境では次の状態でリクエストが出来ています。

    バックエンド

    Laravel 10

    routes/api.php
    Route::get('/check', function() { return ['Hello World']; });
    
    config/cors.php
    return [
        'paths' => ['api/*', 'sanctum/csrf-cookie'],
        'allowed_methods' => ['*'],
        'allowed_origins' => ['*'],
    // フロントエンドのoriginを設定しても接続できています
    //    'allowed_origins' => ['http://127.0.0.1:5500'],
        'allowed_origins_patterns' => [],
        'allowed_headers' => ['*'],
        'exposed_headers' => [],
        'max_age' => 0,
        'supports_credentials' => false,
    ];
    

    フロントエンド

    http://127.0.0.1:5500/index.html
    <!DOCTYPE html>
    <html>
        <head>
            <script>
                (function () {
                    fetch("http://localhost:8000/api/check")
                        .then((response) => response.json())
                        .then((data) => console.log(data)); // ['Hello World']
                })();
            </script>
        </head>
        <body>
        </body>
    </html>
    
  3. 解決したようで良かったです。
    原因について確認したいのですが、http://localhostはそもそも別のサイトだった、ということでしょうか?

  4. ご協力ありがとうございました。
    別のサイトなのかは少しわからないのですが、
    私の環境はxammp(localhostもしくはlocalhost:80)のディレクトリの上でLaravel(localhost:8000)のプロジェクトを作っています。
    https://blog.future.ad.jp/laravel-on-xampp
    この間Laravelのpublicディレクトリに作ったJSONファイルを読み込みたい時がありました。その際はlocalhost(80)のほうを指定していないとURLが存在しない(404)とエラーになっていました。今回コントローラーにアクセスする時もlocalhost:80と指定していないといけないと勝手に思い込んでいましたがlocalhost:8000(Laravel自体のオリジン)を指定しないといけないということが今回わかりました。(シンプルなgetメソッドをテストでリクエストした際、404エラーが出て気づきました。) 結果Laravelのオリジンを指定していなかったことで404エラーになっていたと考えております。

  5. 回答ありがとうございます。
    詳細はわかりませんが、XAMMPでapacheを起動して、さらにphp artisan serveも起動されている状態なのかなと思いました。
    そうであれば、どちらに接続するかで話は変わってきますね。

Your answer might help someone💌