zoukankan      html  css  js  c++  java
  • ASP.NET 重复点击请求导致数据库中出现重复

    产生原因

    由于重复点击或者网络重发

    eg:

    点击提交按钮两次;

    点击刷新按钮;

    使用浏览器后退按钮重复之前的操作,导致重复提交表单;

    使用浏览器历史记录重复提交表单;

    浏览器重复的HTTP请求;

    nginx重发等情况;

    分布式RPC的try重发等;

    主要有 2 个部分:

    (1)前端用户操作

    (2)网络请求可能存在重试

    当然也不排除一些用户的恶意操作。

    问题

    就是同一份信息,重复的提交给服务器。

    场景

    1. 点击F5刷新页面: 当用户点击submit将已经写好的表单数据提交到服务器时,可以在浏览器的url看到地址和参数的变化,但因为网速等问题,用户当前页面并未刷新,或者点击刷新页面,造成表单重复提交。

    2. 重复点击提交按钮: 因为网络问题,未能及时跳转显示内容,部分用户可能会出于心急重复提交提交按钮,造成多次提交内容到服务器。

    3. 前进后退操作 :有些用户在进行某些工作操作时,可能出于需要或者某种情况,进行后退操作,浏览刚才填入的信息,在进行后退和前进的操作可能也会造成表单数据重复提交到服务器。

    4. 使用浏览器历史记录重复访问: 某些用户可能会出于好奇,利用浏览器的历史记录功能重复访问提交页面,同样会造成表单重复提交问题。

    解决思路

    前端

    方案一:禁用按钮提交

    设置标志位,提交之后禁止按钮。像一些短信验证码的按钮一般都会加一个前端的按钮禁用,毕竟发短信是需要钞票滴~

    ps: 以前写前端就用过这种方式。

    • 优点

    简单。基本可以防止重复点击提交按钮造成的重复提交问题。

    • 缺陷

    前进后退操作,或者F5刷新页面等问题并不能得到解决。

    最重要的一点,前端的代码只能防止不懂js的用户,如果碰到懂得js的编程人员,那js方法就没用了。

    方案二:设置HTTP报头

    设置HTTP报头,控制表单缓存,使得所控制的表单不缓存信息,这样用户就无法通过重复点击按钮去重复提交表单。

    <meta http-equiv="Cache-Control" content="no-cache, must-revalidate">

    但是这样做也有局限性,用户在提交页面点击刷新也会造成表单的重复提交。

    方案三:通过 PRG 设计模式

    用来防止F5刷新重复提交表单。

    PRG模式通过响应页面Header返回HTTP状态码进行页面跳转替代响应页面跳转过程。

    具体过程如下:

    客户端用POST方法请求服务器端数据变更,服务器对客户端发来的请求进行处理重定向到另一个结果页面上,客户端所有对页面的显示请求都用get方法告知服务器端,这样做,后退再前进或刷新的行为都发出的是get请求,不会对server产生任何数据更改的影响。

    这种方法实现起来相对比较简单,但此方法也不能防止所有情况。例如用户多次点击提交按钮;恶意用户避开客户端预防多次提交手段,进行重复提交请求;

    下面谈一谈后端的防止重复提交。

    后端

    幂等性

    如果是注册或存入数据库的操作,可以通过在数据库中字段设立唯一标识来解决,这样在进行数据库插入操作时,因为每次插入的数据都相同,数据库会拒绝写入。

    这样也避免了向数据库中写入垃圾数据的情况,同时也解决了表单重复提交问题。

    但是这种方法在业务逻辑上感觉是说不过去的,本来该有的逻辑,却因为数据库该有的设计隐藏了。

    而且这种方法也有一定的功能局限性,只适用于某系特定的插入操作。

    • 实现方式

    这种操作,都需要有一个唯一标识。数据库中做唯一索引约束,重复插入直接报错。

    • 缺点

    有很大的约束性。

    一般都是最后的一道防线,当请求走到数据库层的时候,一般已经消耗了较多的资源。

    直接加锁

    为了避免短时间的重复提交,直接使用加锁的方式。

    优点:不需要前端配合修改,纯后端。

    缺点:无法像 token 方法,准确的限定为单次。只能限制固定时间内的操作一次。

    个人理解:前端的方式依然是防君子不防小人。直接通过限制固定时间内无法操作,来限制重复提交。

    这个时间不能太长,也不能太短,一般建议为 10S 左右,根据自己的真实业务调整。

    锁也是同样的道理,token 其实也可以理解为一种特殊的锁。

    锁同样可以分为单机锁+分布式的锁。

     总结

    设置sql的字段唯一约束  这样就会报错

    设置前端点击之后弹出加载框 防止重复点击

    对方法加锁

  • 相关阅读:
    【Redis破障之路】四:Jedis基本使用
    【JVM进阶之路】十二:字节码指令
    Java学习之Spring MVC路由映射
    Java安全之FastJson JdbcRowSetImpl 链分析
    Allatori混淆动态调试分析
    Java工具开发手记
    Java安全之JBoss反序列化漏洞分析
    docker 应用篇————swarm[二十]
    docker 应用篇————docker-compose[十九]
    docker 应用篇————docker 自定义网络[十八]
  • 原文地址:https://www.cnblogs.com/netlock/p/14246381.html
Copyright © 2011-2022 走看看