HTTP PATCH 的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
httpbin - 协议调试工具
httpstatuses - 协议状态码查询
httpie - cURL-like tool for humans
Fiddler
acr0ss
V2EX    HTTP

HTTP PATCH 的问题

  •  
  •   acr0ss 2020-06-13 00:05:13 +08:00 3254 次点击
    这是一个创建于 1996 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作为一个 CRUD boy,最近想要努力将 RESTful 付诸实践。 但是有一个问题一直困扰着我:

    修改数据该选用哪个 verb ? PUT 、POST 或是 PATCH ?

    从语意来说,POST 是新增,PUT 是修改,PATCH 是部分修改。 从幂等性来说,POST 是非幂等的,而 PUT 和 PATCH 是幂等的。

    现在我有两个问题

    1. 如果是 incr field 操作,PUT 和 PATCH 无法做到幂等,这种情况下各位老哥会如何抉择?
    2. PATCH 这个动词,实践中会使用吗?使用的多吗?
    6 条回复    2020-06-22 19:48:22 +08:00
    yyfearth
        1
    yyfearth  
       2020-06-13 03:05:26 +08:00   1
    inc field 这个操作本身不是幂等的
    直接放到 PUT 和 PATCH method 都不合适

    比如 /object/11111/count 需要 inc 操作
    那么 PUT 和 PATCH 都应该是直接对 count 进行赋值 而不是 INC 的操作
    而赋值是幂等的

    如果非要支持 INC 操作 那么应该用 POST 比如 POST /object/11111/count/inc 或者 POST /object/11111?op=incCount 这样比较合适
    PUT 一般对应 db 的 replace 功能 替换记录
    PATCH 一般是 update 功能 部分修改
    askfermi
        2
    askfermi  
       2020-06-13 03:10:03 +08:00   1
    PATCH 应该是不必幂等的。

    "A PATCH is not necessarily idempotent, although it can be."

    ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH
    jadec0der
        3
    jadec0der  
       2020-06-13 04:29:10 +08:00   1
    incr field 具体是什么操作呢?

    如果非要幂等的话可以考虑先 POST 一个 transaction,然后用 PUT/PATCH 把 transaction 状态改成确认。当然我觉得这就太教条了。
    acr0ss
        4
    acr0ss  
    OP
       2020-06-13 09:45:09 +08:00
    @askfermi 这个文档写的很详细,也回答了我的问题,感谢!
    crclz
        5
    crclz  
       2020-06-21 15:28:44 +08:00
    https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md#74-supported-methods

    和前面 Mozilla 的问答一样,微软的文档指出
    PATCH ; Apply a partial update to an object ; Is Idempotent:False


    关于 patch 还有一点,就是 patch 一般是提交多个字段:

    例如我有个资源(或者数据库表),叫“离校请求”,有(学生 id,离校时长、离校原因、是否同意)几个字段。
    那么,很容易想到的 patch 的请求就是 PATCH /离校请求 /123,body 是{离校时长:10 小时,离校原因:看病}。然后服务端在判断的时候,如果传过来的哪个字段不为 null,那么就代表客户端想要更新这个字段。这就做到了节省代码行数(只需写一个接口)。 当然,如果想要让客户端有能力将某个字段置为 null,就约定一个悬空值。

    在这个场景中,对于“教师同或拒绝离校申请”的功能,这个功能不是单纯的修改某一字段的值,还可能会有副作用,例如修改另外一个表“User”的“是否允许离校”字段。对此,有的人可能会单独开一个接口,例如`/离校请求 /11/处理请求`。

    其实同意或拒绝离校申请这种也可以包含到 patch 请求体里面。
    PATCH /离校请求 /11 。body 的 schema 就变成是:{离校时长:string?,离校原因:string?, 是否同意: bool? }。

    这样的好处是节省代码,并且接口整洁。

    当然,不同用户对于字段的权限不同,在 controller 代码里面应该是这样的结构:
    ``` cs
    if body.离校时长!=null {
    if 当前用户有权限修改离校市场{
    修改离校时常
    }
    }

    if body.离校原因 != null {
    .........
    }

    保存更改
    ```
    acr0ss
        6
    acr0ss  
    OP
       2020-06-22 19:48:22 +08:00
    @crclz 那实际运用中,PATCH 用的多吗?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2267 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 15:48 PVG 23:48 LAX 07:48 JFK 10:48
    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