Laravel API 何故かコントローラーの関数を用いて値を返すと405エラーを返す


概要

  • LaravelをAPIサーバーとして用いてとあるルーティングにリクエストを送ったが405を返す問題が発生してちょっと詰まったので原因をまとめる。

問題発生までの経緯

  • 下記の様にルーティング、コントローラーに記載を行った。

    • ルーティング

      web.php
      // thunder client動作確認用
      Route::get('/get_test', function(){
          return 'ROOT GET OK';
      });
      Route::post('/post_test', function(){
          return 'ROOT POST OK';
      });
      
      Route::post('/send', [LineMessageController::class, 'send']);
      
    • コントローラー

      TestController.php
      public function send(GetSendRequest $request)
      {
          return 'XXX';
      }
      
  • DockerでPHPコンテナ内にApacheを立てている。

  • ローカルの8000ポートをコンテナ内の80ポートにフォワーディングしている。

  • app/Http/Middleware/VerifyCsrfToken.php$exceptの配列にpost_testsendを追加した。

  • VScodeのThunder Clientを用いてそれぞれ下記のURLにリクエストを投げた。

問題発生

  • http://localhost:8000/sendにリクエストを投げたときだけ405 Method Not Allowedが帰ってきた。

    Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: The POST method is not supported for this route. Supported methods: GET, HEAD. in file /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php on line 118
    

問題解消までの経緯

  1. Thunder Clientに登録しているリクエストのURLに誤りが無いことを確認 → 問題なさそう。

  2. ルーティングファイルで当該のルート情報がpostになっている事を確認 → 問題なさそう。(なぜ「Supported methods: GET」と言われているのか分からない。)

  3. 「Supported methods: GET」と言われているので当該のルート情報のgetで受け付ける様に修正して実行してみた。

    web.php
    Route::get('/send', [LineMessageController::class, 'send']);
    
  4. 下記のエラー405 Method Not Allowedが帰ってきた。

    Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: The GET method is not supported for this route. Supported methods: POST. in file /var/www/html/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php on line 118
    
  5. 「Supported methods: POST.」と帰ってきてプチパニック(「Supported methods: GET.」って言われたからGETにしてリクエスト送ったのに「Supported methods: POST.」ってなんでや)

  6. 下記の知見を発見したが、自分のリクエストを確認して問題無かった。

  7. 下記の様にルーティングに記載して、コントローラーを呼び出しているルーティングはコメントアウトした。

    Route::post('/send', function(){
        return 'ROOT SEND POST OK';
    });
    
  8. ↑これだと「ROOT SEND POST OK」の文字が帰ってくる。どうやらコントローラーのメソッドに問題がありそう。

  9. もう一度当該のコントローラーの当該の関数をよく見てみる。

    TestController.php
    public function send(GetSendRequest $request)
    {
        return 'XXX';
    }
    
  10. よく見たら独自に作成したリクエストクラスであるGetSendRequestを通してデータが当該関数に入ってきている。

  11. GetSendRequestを見たところ、Postしていない値が必須バリデーションされていた。下記の様に修正したら「XXX」の文字が返された。

    TestController.php
    use Illuminate\Http\Request;    
    
    public function send(Request $request)
    {
        return 'XXX';
    }
    

原因

  1. 意図しないバリデーションが設定されていた。
  2. リクエストのテストでは何も値をPostしていなかったため、バリデーションエラーが発生 → エラー画面へのリダイレクトが行われたが、リダイレクト先のルーティングがGETで定義されていたため「Supported methods: GET,」のエラーが出たものと思われる。