84
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Laravelで405や419エラーに遭遇した場合の対処法

Posted at

最近、Laravel の勉強をしていて遭遇したエラーをまとめておきます。うっかりミスでも、情報がないと、意外と原因に気づくのに時間がかかるもので・・・。

まとめ

  • HTTP ステータスコードが 405 の場合
    • ルーティングの定義漏れ
  • HTTP ステータスコードが 419 の場合
    • CSRF 対策漏れ

前提

  • Laravel 5.7

405

  • 別名 「MethodNotAllowedHttpException」

事象

例えば、routes/web.php で、/auth/login という URL に対して、以下のように定義されている場合。

routes/web.php
// GET メソッドは定義済
Route::get('/auth/login', 'LoginController@show');

// POST メソッドは未定義
// Route::post('/auth/login', 'LoginController@authenticate');

この場合に、POST メソッドにアクセスすると、405 エラーが発生します。1

スクリーンショット 2019-01-02 18.53.00.png

解決策

ルーティングを正しく定義しましょう。

routes/web.php
// GET メソッドは定義済
Route::get('/auth/login', 'LoginController@show');

// POST メソッドも定義する
Route::post('/auth/login', 'LoginController@authenticate');

419

事象

例えば、Blade テンプレートで、以下のようなログインフォームを作成した場合。

<form action="/auth/login" method="post">
    <div class="form-group">
        <label for="email">メールアドレス</label>
        <input type="email" name="email" class="form-control" value="{{ old('email') }}">
    </div>
    <div class="form-group">
        <label for="password">パスワード</label>
        <input type="password" name="password" class="form-control">
    </div>
    <button type="submit" class="btn btn-primary">ログイン</button>
</form>

この場合に、「ログイン」ボタンを押すと、419 エラーが発生します。

スクリーンショット 2019-01-02 18.55.23.png

解決策

Blade テンプレートに CSRF 保護 を追加します。
具体的には、@csrf を追加するだけです。

   <form action="/auth/login" method="post">
       <!-- CSRF保護 -->
       @csrf
       
        <div class="form-group">
            <label for="email">メールアドレス</label>
            <input type="email" name="email" class="form-control" value="{{ old('email') }}">
        </div>
        <div class="form-group">
            <label for="password">パスワード</label>
            <input type="password" name="password" class="form-control">
        </div>
        <button type="submit" class="btn btn-primary">ログイン</button>
    </form>

与太話

@csrf が追加されたのは Laravel 5.6 からです。5.5 以前は {{ csrf_field() }} でした。5.6 以降でも {{ csrf_field() }} も使えるようですが、個人的には @csrf のほうが覚えやすくていいかなと思います。

また、同様に、PUT・PATCH・DELETE メソッドを使う際に記述していた {{ method_field('PUT') }} も、@method('put') が追加されています。

あとがき

公式ドキュメントに一言書いてあると嬉しかったですね。いや、これぐらい、すぐ分かれよ(そもそも、そんなミスするなよ)という話なのかもしれませんが。

参考

おまけ

どうやって POST メソッドをテストすればいいんだろう? と少し悩んでしまいました。
最初は Request のモックを作るのかなと思いきや、公式ドキュメント にちゃんと注意書きがありました。

Note: Requestファサードをモックしてはいけません。代わりに、テスト実行時はgetやpostのようなHTTPヘルパメソッドへ、望む入力を引数として渡してください。

例えば、「POST メソッドで情報を送信し、正しくリダイレクトされたか?」を確かめたい場合は、以下のように post() を使えば良いらしいです。

LoginControllerTest
class LoginControllerTest extends TestCase
{
    // テストで入れたデータはテスト後に削除する
    use RefreshDatabase;

    /**
     * @test
     */
    public function ログインに成功すること()
    {
        // ユーザーを1人作成する
        $users = factory(\App\User::class, 1)->create();

        // POSTで送信したい情報を第2引数に渡す
        $response = $this->post('/auth/login', [
            'email'     => $users[0]->email,
            'password'  => 'secret',
        ]);

        // リダイレクトが成功したかを確認する
        $response->assertRedirect('/');
    }
}

ちなみに、これを実行して 405 エラーが出ると、こんな感じになります。

スクリーンショット 2019-01-02 18.58.13.png
  1. ちなみに、GET メソッドも定義されていない(/auth/login に対して全く定義されていない)場合は、みんな大好き、404 エラーが発生します。

84
55
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
84
55

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?