在 ASP.NET MVC 中,有哪些方法可以停止表单的多次回发?
-
23-08-2019 - |
题
一个常见的 Web 问题是用户多次单击表单的提交按钮,因此服务器多次处理该表单。当用户提交表单后点击后退按钮并再次处理表单时,也会发生这种情况。
在 ASP.NET MVC 中阻止这种情况发生的最佳方法是什么?
我认为的可能性是:
- 提交后禁用按钮 - 这会绕过多次点击,但不会绕过导航
- 立即重定向接收操作 - 浏览器似乎将这些重定向排除在历史记录之外
- 在会话和表单上放置一个唯一的令牌 - 如果它们匹配,则处理表单 - 如果不清除表单以进行新提交
还有更多吗?
其中有一些具体的实现吗?
我可以看到第三个选项被实现为带有 HtmlHelper 扩展的 ActionFilter,其方式与防伪功能类似。
期待收到你们 MVC 人员的来信。
解决方案
人们常常忽略处理这个问题的最传统方法,即使用 随机数键.
您可以使用 PRG 正如其他人提到的,但 PRG 的缺点是它不能解决双击问题,它需要额外访问服务器进行重定向,并且由于最后一步是 GET 请求,因此您无法直接访问到刚刚发布的数据(尽管它可以作为查询参数传递或在服务器端维护)。
我喜欢 Javascript 解决方案,因为它有效 最多 的时间。
随机数键 然而,一直在工作。随机数密钥是由服务器生成的随机唯一 GUID(也保存在数据库中)并嵌入到表单中。当用户发布表单时,随机数键也会被发布。一旦 POST 进入服务器,服务器就会验证其数据库中是否存在随机数密钥。如果是,服务器将从数据库中删除该密钥并处理该表单。因此,如果用户 POST 两次,则不会处理第二次 POST,因为在处理第一个 POST 后,随机数键已被删除。
随机数密钥还有一个额外的优点,即它通过防止 重放攻击 (中间的人嗅探您的 HTTP 请求,然后将其重播到服务器,服务器将其视为合法)。
其他提示
您应该始终返回重定向作为 POST 的 HTTP 响应。这将防止当用户使用浏览器中的“前进/后退”按钮来回导航时再次发生 POST。
如果您担心用户双击您的提交按钮,只需使用一个小脚本在提交时立即禁用它们即可。
您可能想看看 重定向后获取 (PRG)模式:
这确实不是 MVC 特有的,但我们在网页上遵循的模式是通过 AJAX 调用而不是整页 POST 来执行操作。因此,导航到 url 不会执行任何操作,只会显示表单。AJAX 调用不会出现在历史记录中
除了禁用按钮之外,您还可以在整个网页上添加一个透明的 div,这样单击就不会执行任何操作。我们在我的工作中这样做,并添加一个友好的标签,说明处理请求。
我发现的最优雅的解决方案是使用 ActionFilters: