我遇到的问题如下:
iOS 客户端因为第一次打开应用需要用户允许网络访问权限
,导致第一次发送请求(用于分配帐号)总是在同一时间(1 秒钟内)重复发送多次(2-3 次)。
这样就导致服务端会为这个 uuid 的设备创建多个分配帐号,虽然产品逻辑上是允许一个 uuid 通过另一个注册接口去注册多个帐号,但是并不允许在第一次打开 app 的时候分配多个帐号,所以就导致我无法通过为 uuid 创建数据库约束来避免这种情况。
请问如果不从客户端下手,API 后端如何避免让一个 uuid 在 1 秒钟内同时创建多个帐号?
在写完这个帖子后,我想到一个办法,就是为uuid
和created_at
创建联合唯一约束,本着深入研究的精神,想请求除了这个还有别的更好办法吗?
为 uuid 和 created_at 创建联合唯一约好像不行吧?created_at 的精度不是秒。 一个做法是生成账号后,缓存里面给这个 uuid 设个值,以一个过期时间。每次建的时候先查缓存,没有再建新的。
created_at 的类型是 datetime,精度应该就是秒吧?
在缓存里设置 uuid 肯定不行,同一秒发生的请求,缓存也会同时两个一起查和写,
mysql 5.7 是秒后面还有小数 有https://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html
默认不加参数的 datetime 后面并没有小数,mysql 5.7,刚测试给uuid
和created_at
加联合唯一索引,用批量插入语句,uuid
和created_at
一样的情况下,触发了Duplicate entry '96f2bfe9-3ed2-4721-a7c8-57185e283fc2-2017-06-08 19:39:41' for key 'uuid_created_at'
。
说明是可用的办法。
我跟楼主遇到过一样的问题。这个在后端加一个重复请求拒绝的功能就好了,一模一样的参数你 1 秒内已经收到过,你就返回 400。不过前提是你的参数里面,要带上区分用户的东西,比如用户的 token,或者设备的 uuid,或者加上对方网络的 ip 地址。 实现的方法就很多了,rails 的缓存也行,redis-object 也有类似的存储功能。
有时候客户端很多这种重复提交的问题,不只是一个接口调用,也有 web 端的按钮不加点击后禁用这类问题,你没法控制这么多客户端的页面,所以后端还是得有自己的机制。
客户端的锅不能都砸到后端,这种问题应该先从客户端下手解决问题,web 点击不禁用那就改,不是所有地方都要必须要检验,关键流程比如提交控制好就行,自己的产品这些做不好说不过去吧
然后是后端对提交特征值的校验,比如设备 id,时间戳,ip