Web项目如何防止客户端重复发送请求

在Web项目中,有一些请求或操作会对数据产生影响(比如新增、删除、更新),针对这类请求一般都需要做一些保护,以防止用户有意或无意的重复发起这样的请求导致的数据错乱。

本文总结了一些防止客户端重复发送请求的方法。

方法一:JS监听Form的onsubmit事件

在经典场景下,浏览器通过Form发送请求。因此只需要在Form onsubmit时将Submit按钮disable,就能够防止用户双击导致的重复请求(这种问题一般发生在年纪大的用户身上,他们分不清单击和双击)。

但是随着前端的发展,Form以外的请求方式也越来越多,比如利用各种前端框架(Vue、AngularJs、Backbone等)写的App,他们更多的采用的是ajax的方式和后端交互。那么前端开发人员必须在开发时针对每个代表发起请求的UI元素做处理,像Form一样,在发起请求的时候把相关UI元素禁用掉。

而有些交互方式则可能连代表发起请求的UI元素都没有,比如Segmentfault的markdown编辑器就是在一边输入的时候一边保存的。那么这时就需要前端代码采用其他手段来控制重复请求的发生。

优点:

  1. 不需要后端写代码

缺点:

  1. 不存在统一的解决方案,必须针对每种情况写处理代码
  2. 无法控制浏览器刷新发起的重复请求
  3. 前端开发人员忘记写相关代码
  4. 无法控制恶意的重复请求,比如绕过浏览器直接发起

方法二:Http Status Code 302(后端重定向)

服务端采用重定向的方式,防止用户刷新浏览器发出重复请求。这是比较经典的后端控制重复请求的方式,因为一旦重定向成功后,用户刷新浏览器所刷新的是那个重定向地址,而不是数据操作地址。

优点:

  1. 不需要写前端代码

缺点:

  1. 在还未响应302之前,所发起的重复请求,比如:用户快速的双击、刷新浏览器
  2. 在某些前端程序里(比如SPA),不能使用重定向
  3. 后端开发人员忘记写相关代码
  4. 无法控制恶意的重复请求,比如绕过浏览器直接发起

方法三:结合方法一和方法二

结合方法一和方法二的话倒是可以解决大部分问题,但是解决不了以下问题:

  1. 在还未响应302之前,用户刷新浏览器导致的重复请求
  2. 有些场景下压根不能使用重定向
  3. 前、后端开发人员忘记写相关代码
  4. 无法控制恶意的重复请求,比如绕过浏览器直接发起

方法四:token方式

token的流程是这样的:

  1. 在浏览器发送请求前,先到服务端索要token
  2. 浏览器发送请求时,将token一并提交
  3. 服务端检查请求是否携带token、token是否有效(比如是否正确、是否过期)。如果不正确则响应失败;如果正确则销毁token,继续业务逻辑。

关键点在于:

  1. 每个token都是一次性且有过期时间的,能够防止token前端代码bug造成的重复利用和无限利用。
  2. 服务器要求请求必须携带token,能够避免前端开发人员漏写相关代码。

那么token是以怎样的形式传输的呢?我认为有以下两种方式:

Cookie

推荐使用这种方式,因为浏览器每次都会将cookie携带在请求里一并发出,所以前端发送请求的代码都不需要修改,只要在发送请求前问服务器拿token就行了。

比如在进入Form页面时,服务器将token以cookie的形式一并携带在响应中,那么前端Form提交时,就会将cookie一并携带在请求中,前端的代码一点都不需要修改。

json

前端发起ajax请求像后端拿token,后端以json的形式返回token,前端发送请求时将token携带在请求中,后端检验。

这种方式比Cookie稍微麻烦的地方是,前端必须写一些代码来保存这个token,然后在发送请求的地方要写一些代码把token携带在请求里。

优点

  1. 前端代码可以写的少一些,比如禁用UI元素的代码可以不写
  2. 能够解决在还未响应302之前,用户刷新浏览器导致的重复请求
  3. 适应有些场景下压根不能使用重定向

缺点

  1. 前、后端开发人员忘记写相关代码。这个真的解决不了。
  2. 无法控制通过脚本运行的,具有整套流程的恶意请求。这种请求在程序看来完全合法,但却属于恶意行为,针对这类恶意行为的防控属于另一个话题,本人不懂,所以在这里就不多讲了。

方法五:利用数据库的唯一约束

如果请求会insert数据,而这个数据正好存在业务主键,那么可以利用数据库的唯一约束来做进一步的防御。

方法六:请求幂等化

有些业务情形下,请求是幂等的,这就意味着可以不用为重复发生请求而烦恼了——至少在业务逻辑层面不用烦恼了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值