yii2page-caching

Yii When using PageCaching in ajax call not working


I was trying to implement page caching in Yii2 advanced project and everything seemed to be super cool. And suddenly I was hit by a strange issue.

Case: On the homepage of the website there is some dynamic data like showing records from DB, info of current user like the name (if the user is logged-in) and some static content. Also, a search input field which fetches result using AJAX call.

To speed page loading I implemented PageCaching provided by Yii2. And all worked good. But one issue I got stuck at is that after user log-in the ajax call didn't work and gave Error:

Bad Request (#400): Unable to verify your data submission.

I get this error till cache is refreshed after the set duration or I disable cache.

Is this issue related to cookie/session or something else? How to resolve it?


Solution

  • The 400 Bad Request is because the csrf-token is not being sent, with the request which is required to prevent cross-site attacks by Yii whenever you use POST to submit a page or ajax request, if you create an ActiveForm then it creates an input automatically with the token value.

    You didn't add the code that you are using for the ajax call so not clear if you are using it for only one field or the whole form, so I would suggest the concerning part only.

    You need to send the csrf-token and you can get it via javascript using yii.js and calling these 2 methods

    The csrfParam name is configured inside your frontend/config.php or config/web.php depending on the app you are using (advance /basic) under the request component like below

    'components'=>[
        ......
        ......
        'request' => [
            'csrfParam' => '_csrf-frontend',
        ],
        ......
        ......
    ]
    

    So what you need to do is either change the request method from POST to GET and send data via query string or use the following way to send the POST request.

    Note: You should change the URL and add the csrf data into your existing data that you are sending with the request

    let data={};
    data[yii.getCsrfParam()]=yii.getCsrfToken();
    $.ajax(
        {
            method:"POST",
            url:"/site/test",
            data:data,
            success:function(data) {
                console.log(data);
            },
            error:function(jqXHR,textStatus,errorThrown) {
                console.log(jqXHR,textStatus,errorThrown);
            }
        }
    );
    

    If you have a test action inside the SiteController with the following code, then the above ajax call should show you the $_POST array inside the console with the csrf param and token value as key=>value.

    public function actionTest()
    {
        print_r($_POST);
    }