12

背景:我们正在编写注册/支付页面,我们的理念是首先在服务器端编码所有验证和错误检查,然后添加客户端验证作为第二步(非阻塞 jQuery)。

我们想禁用双击服务器端,所以我们编写了一些锁定的、线程安全的代码来处理同时发布/竞争条件。当我们尝试对此进行测试时,我们意识到我们不能导致同时发布或竞争条件发生。

我认为(无论如何在旧浏览器中)双击提交按钮的工作方式如下:

  • 用户双击提交按钮。
  • 浏览器在第一次点击时发送一个帖子
  • 在第二次单击时,浏览器取消/忽略初始帖子,并启动第二个帖子(在第一个帖子返回响应之前)。
  • 浏览器等待第二个帖子返回,忽略初始帖子响应。

我认为从服务器端看起来像这样:服务器同时收到两个发布请求,执行并响应它们(不知道没有人在听第一个响应)。

根据我们的测试(FireFox 3.0、IE 8.0),实际情况如下:

  • 用户双击提交按钮
  • 浏览器为第一次点击发送一个帖子
  • 浏览器排队第二次点击,但等待第一次点击的响应。
  • 响应从第一次单击返回(响应被忽略?)。
  • 浏览器发送第二次点击的帖子。

所以从服务器端:服务器接收它执行并响应的单个帖子。然后,服务器接收到它执行并响应的第二个请求。

我的问题是,这是否一直如此(而且我正在失去理智)?或者这是现代浏览器中的一项新功能,可以防止同时将帖子发送到服务器?

似乎对于服务器端双击预防,我们不必担心同时发布或竞争条件。只需要担心排队的帖子。

4

3 回答 3

4

您需要处理的类似情况(javascript disable-submit-button 解决方案未涵盖)是用户单击提交的情况,服务器处理请求,但在处理用户的互联网连接时(可能他们在进入隧道的火车上)。

当火车从隧道出来时,用户不知道他们的交易是否成功——他们按下了按钮,但页面上没有任何变化(或者他们得到了一个“再试一次”页面)。他们自然会再次单击提交(或“重试”按钮)。

处理这种情况的最佳方法是在表单中包含一个唯一的交易 ID(在隐藏字段中)。随机生成这个id,当一个事务处理成功后,将其存储在数据库中的一个已完成事务列表中。

然后,当您收到 POST 时,检查是否已看到此交易 - 如果有,请直接跳到状态页面。大致:

BEGIN TRANSACTION

SELECT *
FROM completedTransactions
WHERE userId = ... AND transactionId = ...

<if we got a result - display results of previous transaction>

<otherwise - process the request as normal>

INSERT INTO completedTransactions (userId, transactionId)
VALUES (....)

END TRANSACTION

这样做的好处是(假设您有一个正确支持交易的数据库 - 并且因为您正在处理付款,我希望您这样做!)您不需要做任何类型的线程或锁定 - 事情“正常工作”。

(虽然要小心 - 如果存在并发问题,某些数据库系统可以任意中止您的事务 - 但这种(罕见的)情况很容易使用重试循环处理......)

至于测试来自浏览器的双击:如果在两次“提交”点击之间按下“停止”按钮会有什么不同吗?

于 2010-05-19T18:26:03.860 回答
1

这可能是一个愚蠢的反应,但你为什么不只是在点击时禁用带有 javascript 的提交按钮,所以你不必担心多次点击。我通常在我制作的大多数表格上这样做,它似乎解决了这个问题。

您已经说过您正在使用javascript,所以这不是问题吗?

于 2010-05-19T01:42:13.190 回答
0

只要请求处于连接或发送阶段,在第一次提交期间单击提交会取消请求,在服务器“不知道”的情况下启动一个新请求。

于 2010-05-08T05:59:42.633 回答