Web项目如何防止客户端重复发送请求
在Web项目中,有一些请求或操作会对数据产生影响(比如新增、删除、更新),针对这类请求一般都需要做一些保护,以防止用户有意或无意的重复发起这样的请求导致的数据错乱。
本文总结了一些防止客户端重复发送请求的方法。
方法一:JS监听Form的onsubmit事件
在经典场景下,浏览器通过Form发送请求。因此只需要在Form onsubmit时将Submit按钮disable,就能够防止用户双击导致的重复请求(这种问题一般发生在年纪大的用户身上,他们分不清单击和双击)。
但是随着前端的发展,Form以外的请求方式也越来越多,比如利用各种前端框架(Vue、AngularJs、Backbone等)写的App,他们更多的采用的是ajax的方式和后端交互。那么前端开发人员必须在开发时针对每个代表 发起请求的UI元素做处理,像Form一样,在发起请求的时候把相关UI元素 禁用掉。
而有些交互方式则可能连代表 发起请求的UI元素都没有,比如Segmentfault的markdown编辑器就是在一边输入的时候一边保存的。那么这时就需要前端代码采用其他手段来控制重复请求的发生。
优点:
-
不需要后端写代码
缺点:
-
不存在统一的解决方案,必须针对每种情况写处理代码
-
无法控制浏览器刷新发起的重复请求
-
前端开发人员忘记写相关代码
-
无法控制恶意的重复请求,比如绕过浏览器直接发起
方法二:Http Status Code 302(后端重定向)
服务端采用重定向的方式,防止用户刷新浏览器发出重复请求。这是比较经典的后端控制重复请求的方式,因为一旦 重定向成功后,用户刷新浏览器所刷新的是那个重定向地址,而不是数据操作地址。
优点:
-
不需要写前端代码
缺点:
-
在还未响应302之前,所发起的重复请求,比如:用户快速的双击、刷新浏览器
-
在某些前端程序里(比如SPA),不能使用重定向
-
后端开发人员忘记写相关代码
-
无法控制恶意的重复请求,比如绕过浏览器直接发起
方法三:结合方法一和方法二
结合方法一和方法二的话倒是可以解决大部分问题,但是解决不了以下问题:
-
在还未响应302之前,用户刷新浏览器导致的重复请求
-
有些场景下压根不能使用重定向
-
前、后端开发人员忘记写相关代码
-
无法控制恶意的重复请求,比如绕过浏览器直接发起
方法四:token方式
token的流程是这样的:
-
在浏览器发送请求前,先到服务端索要token
-
浏览器发送请求时,将token一并提交
-
服务端检查请求是否携带token、token是否有效(比如是否正确、是否过期)。如果不正确则响应失败;如果正确则销毁token,继续业务逻辑。
关键点在于:
-
每个token都是一次性且有过期时间的,能够防止token前端程序bug造成的重复利用和无限利用,能够避免前端开发人员代码bug。
-
服务器要求请求必须携带token,能够避免前端开发人员漏写相关代码
那么token是以怎样的形式传输的呢?我认为有以下两种方式:
Cookie:
推荐使用这种方式,因为浏览器每次都会将cookie携带在请求里一并发出,所以前端发送请求的代码都不需要修改,只要在发送请求前问服务器拿token就行了。
比如在进入Form页面时,服务器将token以cookie的形式一并携带在响应中,那么前端Form提交时,就会将cookie一并携带在请求中,前端的代码一点都不需要修改。
json:
前端发起ajax请求像后端拿token,后端以json的形式返回token,前端发送请求时将token携带在请求中,后端检验。
这种方式比Cookie稍微麻烦的地方是,前端必须写一些代码来保存这个token,然后在发送请求的地方要写一些代码把token携带在请求里。
优点:
-
前端代码可以写的少一些,比如禁用UI元素的代码可以不写
-
能够解决在还未响应302之前,用户刷新浏览器导致的重复请求
-
适应有些场景下压根不能使用重定向
缺点:
-
前、后端开发人员忘记写相关代码。这个真的解决不了。
-
无法控制通过脚本运行的,具有整套流程的恶意请求。这种请求在程序看来完全合法,但却属于恶意行为,针对这类恶意行为的防控属于另一个话题,本人不懂,所以在这里就不多讲了。
相关 [web 项目 客户端] 推荐:
web项目经理手册
- - 研发管理 - ITeye博客十问Web网站项目
- - 博客园_新闻iOS客户端开发与Web前端开发
- - bang's blogWeb客户端安全性最佳实践
- - 博客 - 伯乐在线xssProject在java web项目中应用
- - Java - 编程语言 - ITeye博客.