V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiaofan2
V2EX  ›  程序员

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

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

    他说的是如果一个人不小心点击两次,生成不同请求如何保证幂等?两次不同请求代表 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 次,怎样保证业务数据唯一性或最终一致性,这样比较准确?防君子只要前端控制,在提交后禁用提交按钮即可。防小人,就是阻挡重放攻击,那么上面很多人已经回答了。
    oneisall8955
        16
    oneisall8955  
       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   ·   我们的愿景   ·   实用小工具   ·   4054 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 10:17 · PVG 18:17 · LAX 03:17 · JFK 06:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.