幂等性原本是数学中的一个概念,用在接口上可以理解为:无论一个接口请求执行多少次,只要请求内容相同,其结果和副作用应该始终一致。在接口设计中,幂等性意味着即使一个请求因网络波动或者用户重复操作被执行多次,系统也不会受到影响,最终的操作结果不变。
在没有实现幂等性的情况下,这些问题会造成系统的不稳定甚至崩溃。
接口幂等性问题通常发生在以下几种情况下:
这些情况都可能导致重复提交相同的请求,进而造成不必要的副作用或错误结果。
为了确保接口的幂等性,我们可以从客户端和服务端两个方面进行防护。虽然客户端的防护方法容易实现,但并不是绝对可靠,因此服务端的校验才是最终保障幂等性的重要措施。
按钮只可操作一次:通过禁用按钮或显示加载状态,避免用户在请求处理中多次点击提交按钮。比如,用户点击提交按钮时,将按钮置灰,并显示“处理中”的状态。
Token机制:为每个请求生成一个唯一的 token,所有的请求都带上这个 token,服务器根据 token 判断是否已经处理过该请求。如果处理过,则直接返回之前的结果,避免重复执行。
使用 Post/Redirect/Get(PRG)模式:提交表单后,执行页面重定向。这样,用户刷新页面或按下浏览器的后退按钮时,不会重新提交表单,避免重复提交的问题。
使用 Session 存储标识符:服务端生成一个唯一标识符并存入 session,前端获取该标识符并作为表单的一部分提交。服务端在接收到请求时,检查标识符是否与 session 中的标识符一致,避免重复提交。
使用唯一索引防止新增脏数据:通过数据库的唯一索引来保证在插入数据时不会重复。例如,使用订单号作为唯一索引,避免重复插入相同的数据。
乐观锁:当更新数据时,可以通过乐观锁来确保只有第一个请求能够成功更新。比如,使用版本号来实现乐观锁,客户端在提交更新时带上当前版本号,服务器只在版本号一致的情况下执行更新操作。
Select + Insert/Update/Delete:在执行数据库操作之前,先进行查询,确保数据符合要求后再执行插入、更新或删除操作。虽然在单机环境下能有效解决幂等问题,但在分布式系统中需要注意并发问题。
分布式锁:在分布式系统中,使用分布式锁来确保同一时间只有一个请求可以处理。这可以通过第三方系统(如 Redis 或 ZooKeeper)来实现,确保操作不会因并发导致重复执行。
状态机幂等性:在处理与状态相关的业务时,可以使用状态机来管理状态的变化。通过检查状态是否已经发生变化,避免重复操作。例如,订单状态已为“已支付”,则再次提交支付请求时就不会改变订单状态。
防重表:例如在支付接口中,使用订单号作为唯一索引插入到防重表中,第一次请求时插入成功,后续重复请求会因为唯一索引冲突而插入失败,从而避免重复支付。
缓冲队列:将请求存入缓冲队列,由后台异步处理。队列中的请求可以过滤掉重复请求,且可以提高系统吞吐量,但不能及时返回结果。
全局唯一号:通过生成全局唯一的序列号或标识符,后端通过该标识符来判断请求是否已处理,确保在高并发环境下不会处理重复请求。
本文作者:han
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!