如何防止在Yii2中提交多个表单?

jek*_*ahm 5 javascript jquery yii2

为了处理表单,我使用以下代码(仅用于测试):

$(document).on("beforeSubmit", "#test-form", function (event, messages) {
    $(this).find(':submit').attr('disabled', true);
    console.log('Test new form');
    return false;
});
Run Code Online (Sandbox Code Playgroud)

但是,尽管我将提交按钮设置为非活动状态,但我们可以在控制台中看到,当我快速单击按钮时,该表单至少提交两次.作为临时修复,编写以下代码:

$(document).on("beforeValidate", "form", function(event, messages, deferreds) {
    $(this).find(':submit').attr('disabled', true);
    console.log('BEFORE VALIDATE TEST');
}).on("afterValidate", "form", function(event, messages, errorAttributes) {
    console.log('AFTER VALIDATE TEST');
    if (errorAttributes.length > 0) {
        $(this).find(':submit').attr('disabled', false);
    }
});
$(document).on("beforeSubmit", "#test-form", function (event, messages) {
    console.log('Test new form');
    return false;
});
Run Code Online (Sandbox Code Playgroud)

但不确定这是一个好的决定.如何解决这个问题?
提前致谢!

Kos*_*kis 5

一种解决方案是使用JavaScript禁用按钮.但是由于浏览器问题或者用户可能在他的浏览器中禁用了JavaScript,因此这种情况一直都不高效.

另一种解决方案是每次在服务器端检查表单是否已使用会话中保存的令牌提交.

可以在https://github.com/yiisoft/yii2/issues/10498中找到以下代码:

模型

public function getHiddenFormTokenField() {
    $token = \Yii::$app->getSecurity()->generateRandomString();
    $token = str_replace('+', '.', base64_encode($token));

    \Yii::$app->session->set(\Yii::$app->params['form_token_param'], $token);;
    return Html::hiddenInput(\Yii::$app->params['form_token_param'], $token);
}
Run Code Online (Sandbox Code Playgroud)

"当表单提交时,控制器类中名为'beforeAction'的函数将发送的令牌与会话中的值进行比较.会话在执行每个操作后被清除.如果值不同,则抛出异常."

调节器

public function beforeAction($action) {
    $formTokenName = \Yii::$app->params['form_token_param'];

    if ($formTokenValue = \Yii::$app->request->post($formTokenName)) {
        $sessionTokenValue = \Yii::$app->session->get($formTokenName);

        if ($formTokenValue != $sessionTokenValue ) {
            throw new \yii\web\HttpException(400, 'The form token could not be verified.');
        }

        \Yii::$app->session->remove($formTokenName);
    }

    return parent::beforeAction($action);
}
Run Code Online (Sandbox Code Playgroud)