[Laravel] ajax を使用したら、HTTPステータス 419 が返ってくるのを解消する

2020年2月14日ITLaravel, PHP

Laravel で ajax を使用して、POSTをしたら、419という見慣れないステータスコードが返ってきたので、それの解消方法です。

POSTのヘッダーかボディにcsrf_tokenを追加してやれば419エラーは解消されます。

[検証環境]
PHP 7.4.2
Laravel 6.14.0

検証スクリプト

下記のようなJavaScriptで id に ajaxTest を持つ要素をクリックしたら、ルート test を叩きにいきます。

<script type="text/javascript">
    $('#ajaxTest').on('click', function(){
        $.ajax({
            url:'test',
            type:'POST',
            data:{
                userid:$('#email').val(),
                passward:$('#passward').val(),
            }
        })
        .done( (data) => {
            console.log(data);
        })
        .fail( (data) => {
            console.log(data);
        });
    });
</script>

web.php には下記のようなルーティングを用意します。

/src/routes/web.php

Route::post('test', function () {
     return 'test success';
});

POSTが成功したら、’test success’ という文字列が返ってきて欲しいのですが

このまま POST しますと、419 ステータスコードが返ってきます。

app.js:16276 POST http://localhost:10080/test 419 (unknown status)

ajaxのPOSTのボディにcsrf_tokenを追加する

先述のJavaScriptに追加します。

<script type="text/javascript">
    $('#ajaxTest').on('click', function(){
        $.ajax({
            url:'test',
            type:'POST',
            data:{
                userid:$('#email').val(),
                passward:$('#passward').val(),
                _token: '{{ csrf_token() }}' // <---ここ
            }
        })
        .done( (data) => {
            console.log(data);
        })
        .fail( (data) => {
            console.log(data);
        });
    });
</script>

これで POST しますと、419 エラーにならず成功します。

ajaxのPOSTのヘッダーにcsrf_tokenを追加する

※Laravel のデフォルトのテンプレート には下記のような meta タグに csrf-token は設定されてますが、必要に応じて設定ください。

<meta name="csrf-token" content="{{ csrf_token() }}">

JavaScriptは下記のようになります。

<script type="text/javascript">
    $('#ajaxTest').on('click', function(){
        $.ajax({
            url:'test',
            type:'POST',
            headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')}, // <--- ここ
            data:{
                userid:$('#email').val(),
                passward:$('#passward').val(),
            }
        })
        .done( (data) => {
            console.log(data);
        })
        .fail( (data) => {
            console.log(data);
        });
    });
</script>

もしくは、ajaxSetup を使用して、、、

<script type="text/javascript">
    $('#ajaxTest').on('click', function(){
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
        $.ajax({
            url:'test',
            type:'POST',
            data:{
                userid:$('#email').val(),
                passward:$('#passward').val(),
            }
        })
        .done( (data) => {
            console.log(data);
        })
        .fail( (data) => {
            console.log(data);
        });
    });
</script>

これで POST しますと、419 エラーにならず成功します。

そもそも 419 エラーとは?

419 エラーは見かけたことがなかったのですが、4XX エラーはクライアント側のエラーです。

HTTPのステータスコード:

https://ja.wikipedia.org/wiki/HTTP%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89#4xx_Client_E

Laravel が内部で使用している例外のハンドラーで 419 を定義していて、TokenMismatchException として、投げているようです。

/vendor/laravel/framew
ork/src/Illuminate/Foundation/Exceptions/Handler.php

/**
    * Prepare exception for rendering.
    *
    * @param  \Exception  $e
    * @return \Exception
    */
protected function prepareException(Exception $e)
{
    if ($e instanceof ModelNotFoundException) {
        $e = new NotFoundHttpException($e->getMessage(), $e);
    } elseif ($e instanceof AuthorizationException) {
        $e = new AccessDeniedHttpException($e->getMessage(), $e);
    } elseif ($e instanceof TokenMismatchException) {
        $e = new HttpException(419, $e->getMessage(), $e); // <--- ここ
    } elseif ($e instanceof SuspiciousOperationException) {
        $e = new NotFoundHttpException('Bad hostname provided.', $e);
    }

    return $e;
}

以上になります。

ここまでお読みいただきありがとうございました。

スポンサーリンク

Posted by nobuhiro harada