- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
面试官问我:你的项目如何处理反复恳求(并发恳求)?
对于一些用户恳求,在某些情况下是可能反复发送的,假如是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦反复了,可能会导致很严峻的后果,例如买卖的接口假如反复恳求可能会反复下单。
反复的场景有可能是:
黑客拦截了恳求,重放 前端/客户端由于某些缘由恳求反复发送了,或者用户在很短的时间内反复点击了。网关重发 …. 本文争辩的是假如在服务端优雅地统一处理这种情况,如何禁止用户反复点击等客户端操作不在本文的争辩范畴。
利用独一恳求编号去重
你可能会想到的是,只需恳求有独一的恳求编号,那么就能借用Redis做这个去重——只需这个独一恳求编号在redis存在,证明处理过,那么就认为是反复的
代码或许如下:
????String?KEY?=?REQ12343456788;//恳求独一编号????long?expireTime?=??1000;//?1000毫秒过期,1000ms内的反复恳求会认为反复????long?expireAt?=?System.currentTimeMillis()?+?expireTime;????String?val?=?expireAt@?+?expireAt;????//redis?key还存在的话要就认为恳求是反复的????Boolean?firstSet?=?stringRedisTemplate.execute((RedisCallback)?connection?-?connection.set(KEY.getBytes(),?val.getBytes(),?Expiration.milliseconds(expireTime),?RedisStringCommands.SetOption.SET_IF_ABSENT));????final?boolean?isConsiderDup;????if?(firstSet?!=?null??firstSet)?{//?第一次访问????????isConsiderDup?=?false;????}?else?{//?redis值已存在,认为是反复了????????isConsiderDup?=?true;????}
业务参数去重
上面的方案能处理具备独一恳求编号的场景,例如每次写恳求之前都是服务端前往一个独一编号给客户端,客户端带着这个恳求号做恳求,服务端即可完成去重拦截。
但是,很多的场景下,恳求并不会带这样的独一编号!那么我们能否针对恳求的参数作为一个恳求的标识呢?
先考虑简约的场景,假设恳求参数只要一个字段reqParam,我们可以利用以下标识去推断这个恳求能否反复。用户ID:接口名:恳求参数
String?KEY?=?dedup:U=+userId?+?M=?+?method?+?P=?+?reqParam;
那么当同一个用户访问同一个接口,带着同样的reqParam过来,我们就能定位到他是反复的了。
但是问题是,我们的接口通常不是这么简约,以目前的主流,我们的参数通常是一个JSON。那么针对这种场景,我们怎样去重呢?
计算恳求参数的摘要作为参数标识
假设我们把恳求参数(JSON)按KEY做升序排序,排序后拼成一个字符串,作为KEY值呢?但这可能格外的长,所以我们可以考虑对这个字符串求一个MD5作为参数的摘要,以这个摘要去取代reqParam的位置。
String?KEY?=?dedup:U=+userId?+?M=?+?method?+?P=?+?reqParamMD5;
这样,恳求的独一标识就打上了!
注:MD5理论上可能会反复,但是去重通常是短时间窗口内的去重(例如一秒),一个短时间内同一个用户同样的接口能拼出不同的参数导致一样的MD5几乎是不行能的。
连续优化,考虑剔除部分时间因子
上面的问题其实已经是一个很不错的处理方案了,但是实际投入使用的时候可能发觉有些问题:某些恳求用户短时间内反复的点击了(例如1000毫秒发送了三次恳求),但绕过了上面的去重推断(不同的KEY值)。
缘由是这些恳求参数的字段里面,是带时间字段的,这个字段标记用户恳求的时间,服务端可以借此丢弃掉一些老的恳求(例如5秒前)。如下面的例子,恳求的其他参数是一样的,除了恳求时间相差了一秒:
????//两个恳求一样,但是恳求时间差一秒????String?req?=?{\n?+????????????\requestTime\?:\20210101120001\,\n?+????????????\requestValue\?:\1000\,\n?+????????????\requestKey\?:\key\\n?+????????????};????String?req2?=
文档评论(0)