【发布时间】:2018-12-23 03:51:31
【问题描述】:
编辑 25.07.2018: 正如 Pawnesh Kumar 在回答中所说,这似乎是浏览器问题。如果我在 Firefox 中多次点击该按钮,下面的脚本只会发送一个 POST 请求,但如果我在 Chrome 中执行相同操作,则每次点击都会收到一个 POST 请求。
但是,我可以在 01:00 在video 中复制该问题。这意味着当我使用Authentication 安装 Laravel 时,如果我点击登录表单中的提交按钮两次,Firefox 将发送 2 个请求。
为什么在多次单击按钮时,Firefox 有时会发送多个 POST 请求,有时只发送一个?
我有一个用户表
id | name
1 | John
其中字段id 是一个主、整数、自动递增键。当我提交一个只有一个按钮的虚拟表单时,这将插入一条名为 John 的新记录。现在这是我观察到的:
如果我提交一次表单,返回浏览器再次提交,然后 我在数据库中发现了两个新行。
如果我通过在
Add上单击两次(或二十次)提交表单 按钮,那么数据库中只有一个新行。
这是为什么呢?我希望如果我多次点击提交按钮,那么表单将发送多个请求 - 并插入多行。
这是我的表格:
<form action="/test.php" method="POST">
<input type="submit" value="Add">
</form>
提交给test.php:
<?php
$servername = "localhost";
$username = "adam";
$password = "password";
$dbname = "test-db";
$conn = new mysqli($servername, $username, $password, $dbname);
$sql = "INSERT INTO user (name) VALUES ('John')";
if ($conn->query($sql) === TRUE) {
echo "New record created successfully";
}
$conn->close();
sleep(4);
由于sleep 部分,我可以连续多次单击Add 按钮。但是,无论我在加载时单击Add 按钮的频率如何,数据库中都只有一个新行。
在我的 access.log 文件中,单击按钮二十次后,我还发现只有一个 GET 和 POST 请求:
2001:****:****:4400:****:****:****:**** - - [25/Jul/2018:11:30:03 +0200] "GET /test/form.php HTTP/1.1" 200 301 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0" "****** *.net"
2001:****:****:4400:****:****:***:**** - - [25/Jul/2018:11:30:34 + 0200]“POST /test/test.php HTTP/1.1”200 31“http://********.net/test/form.php”“Mozilla/5.0(X11;Ubuntu;Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0" "********.net"
备注:
我已经阅读过有关防止多次提交的技术 在backend 或frontend 中。因此我认为应该可以通过多次点击按钮来多次提交表单。
我还在 wiki 文章 Post/Redirect/Get 中读到,如果用户过快地多次提交表单,这种模式无法阻止:
如果由于服务器延迟导致网络用户在初始提交完成之前刷新,导致某些用户代理中出现重复的 POST 请求。
同样在video 1:00 有人双击一个按钮并收到错误,因为他提交了两次。
【问题讨论】:
-
所以,您已经深入挖掘了,只是想确定一下,
{{ csrf_field() }}是否真的在页面重新加载时发生了变化? -
@Eakethet 我编辑了这个问题,希望现在更清楚
-
@Adam 更多,太好了。不知道在 Firefox 中如何,但它应该与在 chrome 中相同。当您疯狂地点击提交按钮二十次时,打开网络监视器并查看事件是如何触发的。该事件被取消,它只需要最后一个事件。多次单击将适用于 - 1) 滞后,2) ajax 表单提交
-
@Eakethet 如果您疯狂地点击提交按钮,您会说只接受最后一个事件。但是,如果您考虑我在评论中提到的视频,那么您会发现用户在 1:00 单击了两次提交按钮并出现错误 - 这是因为第一个帖子刷新了会话中的令牌,第二个提交了令牌与表单中隐藏字段中的令牌不同。所以在这种情况下,第一个帖子没有被取消。
-
您使用的是哪个版本的 PHP?