我想看看 Web 开发人员如何避免重复提交问题。所以基本上我对这个问题的理解如下:
当不耐烦的用户多次提交表单时,会发生双重提交,从而导致问题。这个问题可以通过 JavaScript(特别是 jQuery 脚本)来解决,一旦表单提交就禁用提交按钮 - 如果客户端禁用了 JavaScript,则此问题的一个弱点是。
还有服务器端的检测方法。
所以我的问题是:
人们如何克服双重屈服?双重提交导致问题的真实例子是什么?是否有任何 Web 应用程序框架内置了双重提交工具?
我想看看 Web 开发人员如何避免重复提交问题。所以基本上我对这个问题的理解如下:
当不耐烦的用户多次提交表单时,会发生双重提交,从而导致问题。这个问题可以通过 JavaScript(特别是 jQuery 脚本)来解决,一旦表单提交就禁用提交按钮 - 如果客户端禁用了 JavaScript,则此问题的一个弱点是。
还有服务器端的检测方法。
所以我的问题是:
人们如何克服双重屈服?双重提交导致问题的真实例子是什么?是否有任何 Web 应用程序框架内置了双重提交工具?
如果您正在使用 java 服务器端脚本并且还使用 struts 2,那么您可以参考这个关于使用 token 的链接。
http://www.xinotes.org/notes/note/369/
应为初始页面渲染生成一个令牌并将其保存在会话中,当请求与令牌第一次一起提交时,在 struts 操作中运行一个线程名称作为令牌 id 的线程并运行客户端拥有的任何逻辑请求,当客户端再次提交相同的请求时,检查线程是否仍在运行(thread.getcurrentthread().interrupted)如果仍在运行,则发送客户端重定向 503。
请看struts 2code的ExecuteAndWaitInterceptor,这个逻辑结合token有助于快速点击
使用redirect-after-post或有时称为PRG (post/redirect/get)
简而言之,当用户发布表单时,您执行客户端重定向(在使用发布数据之后)到响应(成功)页面。
一个真实的例子是这个答案发布了两次;-)。如果您不想依赖客户端的任何方面(javascript,甚至 cookie),您可以计算提交数据的 MD5 哈希,可能通过添加源 IP 和使用的浏览器等信息,并拒绝帖子具有相同的哈希值。
如果表单打算为在服务器 dbms 中保存一些数据提供接口,您可以使用对于提交的数据来说是必需的特殊修订字段。检查提交的修订是否与数据库中数据的最新版本匹配(或者是要插入的新数据),可以让您很好地控制在多次提交时应该做什么按顺序。
使用 struts web-application framework 我们可以处理这个问题如下:
Struts 有 3 种方法用于token, saveToken(), isTokenValid() and resetToken()
.
saveToken()
- 生成令牌密钥并保存到请求/会话属性。
isTokenValid()
- 针对请求/会话中的 1 个存储验证提交的令牌密钥。
resetToken()
- 重置令牌密钥。
它是如何工作的:
1) 在加载表单时,调用saveToken()
动作类来创建和存储令牌键。Struts 会将生成的密钥存储在请求/会话中。如果令牌成功创建,在浏览器上查看源代码时会看到类似以下内容,令牌密钥存储为隐藏字段:
<form action="myaction.do" method="post">
<input type="hidden"
name="<%= Constants.TOKEN_KEY %>"
value="<%= session.getAttribute(Action.TRANSACTION_TOKEN_KEY) %>" >
2) 一旦表单提交,isTokenValid()
在动作类上调用,它将使用先前存储在请求/会话中的令牌密钥来验证提交的令牌密钥(隐藏字段)。如果匹配,它将返回 true。
public final ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
saveToken(request);
if (!tokenIsValid(request)) {
//forward to error page saying "your transaction is already being processed"
} else {
//process action
//forward to jsp
}
// Reset token after transaction success.
resetToken(request);
}