今天面试被人问到一个幂等性问题,求大家解惑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
xiaofan2
V2EX    程序员

今天面试被人问到一个幂等性问题,求大家解惑

  •  
  •  
    xiaofan2 2020-08-27 17:04:20 +08:00 7480 次点击
    这是一个创建于 1951 天前的主题,其中的信息可能已经有所发展或是发生改变。

    他说的是如果一个人不小心点击两次,生成不同请求如何保证幂等?两次不同请求代表 token 不同或者前端发送的随机数不同,那如何防止??

    29 条回复    2020-08-29 11:45:27 +08:00
    676529483
        1
    676529483  
       2020-08-27 17:10:25 +08:00
    如果两次点击是误操作,那用一些全局唯一的标识就可以了,比如 uuid 之类的,后端来判断是不是同一次页面的;
    如果是想要防止业务点击多次,那就要业务 参数来幂等了,比如订单号
    lyog
        2
    lyog  
       2020-08-27 17:12:34 +08:00 via iPhone
    如果是我,我会用个分布式锁,然后再加插前查询
    coderxy
        3
    coderxy  
       2020-08-27 17:13:49 +08:00
    1.首先看什么样的接口,如果是 get 请求啥的天然幂等,不需要另外处理
    2.一般这种场景,前端会设计冷却锁。即一个按钮点击后除非请求结果返回或者过了多长时间,才会再次发起请求
    3.如果前端无法控制,那么可以在接口设计上考虑。比如如果是创建一个资源,可以在后端加上并发锁,一个用户只能有一个创建动作在执行,其它请求排队。

    总的来说方案很多,还是要根据实际场景设计。
    takemeaway
        4
    takemeaway  
       2020-08-27 17:14:01 +08:00
    先前端限制不能点两次,方法很多。
    后端再用唯一值和事务限制一下就行了。
    lidlesseye11
        5
    lidlesseye11  
       2020-08-27 17:24:32 +08:00   4
    个人觉得幂等性是业务设计问题,不是技术问题吧。。
    两次请求都不同了凭啥要幂等?
    garlics
        6
    garlics  
       2020-08-27 17:27:31 +08:00
    带上 csrf token ?
    ylsc633
        7
    ylsc633  
       2020-08-27 17:31:12 +08:00   1
    1. web 常见的就是 csrf token
    2. 前端按钮限制仅点击一次
    3. 每个提交地址带个随机参数,用完即废
    4. 数据做幂等插入
    5.etc.
    lipcao
        8
    lipcao  
       2020-08-27 17:31:24 +08:00
    以前做过 aop+redis 锁 防止表单重复提交,但是也是基于 token 来做的,token 都不一样了 不是两次不同的请求吗?一个页面里面存了两个 token ?没看明白
    Evilk
        9
    Evilk  
       2020-08-27 17:45:42 +08:00
    @lidlesseye11 同问
    wysnylc
        10
    wysnylc  
       2020-08-27 17:53:26 +08:00
    yangbonis
        11
    yangbonis  
       2020-08-27 18:55:01 +08:00 via iPhone
    信息安全 重放攻击?
    zjsxwc
        12
    zjsxwc  
       2020-08-27 19:05:39 +08:00 via Android
    get 请求不影响;
    post 请求看业务,有些需求本来不就是幂等的(大部分 post 请求都是),有些需求天生就不能重复(比如需要短信验证码的场景,验证码用过之后里面失效了),有些需求业务上就需要判断是否重复发起(如果检查到重复发起忽略后续处理但返回成功就是幂等,如果检查到重复发起直接报错返回失败就不是幂等)。
    Jooooooooo
        13
    Jooooooooo  
       2020-08-27 19:05:54 +08:00
    前端拦住

    不过业务上两次不同的请求为啥要防止

    这个最终想问的是如何判断是两次有效请求还是一次?
    guagusi
        14
    guagusi  
       2020-08-27 20:01:40 +08:00
    以下单为例,1>用户进入下单页面先请求一个唯一的订单 token ; 2>用户点击下单后,带上 token 提交,下单按钮置灰不可点击; 3>后端校验 token 是否重复; 4>增加同一用户两次请求频率的限制,例如 1s 内多次下单;
    leeg810312
        15
    leeg810312  
       2020-08-27 21:34:04 +08:00 via Android
    问题改成误提交 2 次,怎样保证业务数据唯一性或最终一致性,这样比较准确?防君子只要前端控制,在提交后禁用提交按钮即可。防小人,就是阻挡重放攻击,那么上面很多人已经回答了。
    itechify
        16
    itechify  
    PRO
       2020-08-27 22:15:33 +08:00 via Android
    1.实现幂等性常见的方式有:悲观锁( for update )、乐观锁、唯一约束
    2.几种方式,按照最优排序:乐观锁 > 唯一约束 > 悲观锁
    摘抄自网络,我面试时候也是这么回答的
    npe
        17
    npe  
       2020-08-27 22:19:16 +08:00
    幂等跟原子性、一致性感觉差不多。
    laminux29
        18
    laminux29  
       2020-08-27 22:37:16 +08:00   1
    这事一定要和业务一起考虑。

    举几个场景:

    1.需要支持快速多次点击的场景:比如点外卖,或者淘宝下单,有时候需要快速多次点击增加数量按钮。

    2.需要禁止快速多次点击的场景:比如提交订单按钮,按一次就够了。多按属于业务上的无效操作。

    3.只允许慢速多次点击的场景:比如视频网站的发送弹幕按钮。

    4.只允许慢速单次点击的场景:比如在线考试的多选题。
    opengps
        19
    opengps  
       2020-08-27 22:37:16 +08:00
    保存不成功,客户端的 requestid 不能重新 new
    lihongming
        20
    lihongming  
       2020-08-28 01:09:38 +08:00 via iPhone   1
    要保证幂等性,你总得有一个唯一识别来区分不同的请求。所以你首先得定义唯一识别,比如订单可以用订单号(防止重复支付),帖子可以用内容(比如很多论坛程序不允许连发两个一模一样的帖子),什么都没有的可以用 token 等等。

    如果真像楼主说的两次请求有不同的 token,那是后端设计的问题,前端只能用 js 控制一下重复提交,不可能完全禁止。
    CantSee
        21
    CantSee  
       2020-08-28 01:15:22 +08:00 via Android
    token 唯一性
    xuanbg
        22
    xuanbg  
       2020-08-28 08:34:18 +08:00   2
    首先,这个不是幂等性问题。有 3 个办法可以解决这个问题:
    1 、前端防抖,按钮点击后立即禁用,等接口返回后再视情况启用或跳转页面。
    2 、后端限流,同一来源在一定时间间隔内只允许调用一次。这个方案的好处是通用,且可以顺便减轻接口被非法调用的压力。
    3 、使用令牌,前端提交数据前先获取一个令牌,后端限制令牌只能使用一次。
    Jammar
        23
    Jammar  
       2020-08-28 09:18:29 +08:00
    前端请求之前先获取一段唯一字符串,请求时带上,后端写入了就从缓存里删了
    fdingiit
        24
    fdingiit  
       2020-08-28 16:40:38 +08:00
    @coderxy 不要再误导人了 get 请求一样可以写成不幂等
    coderxy
        25
    coderxy  
       2020-08-28 17:16:58 +08:00   1
    @fdingiit 我说的是按照 restful 风格的规则下。 你要是拿 get 请求做新增操作,那自然是不幂等的。
    ksice
        26
    ksice  
       2020-08-28 18:40:01 +08:00
    感觉防重复提交也可以维持幂等性
    crclz
        27
    crclz  
       2020-08-29 08:21:20 +08:00
    看可以使用幂等接口设计(局限)、ConcurrencyToken (例如实体的 updatedAt )、csrf-token (只能支撑非 spa 的场景
    ) or 客户端生成的 token 。
    buhi
        28
    buhi  
       2020-08-29 09:48:33 +08:00
    幂等性是后端保证的, 不是前端保证的
    youyang
        29
    youyang  
       2020-08-29 11:45:27 +08:00
    @xuanbg agree
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     953 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 19:23 PVG 03:23 LAX 11:23 JFK 14:23
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86