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 · 2751 次点击
    这是一个创建于 1606 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作为一个 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   ·   实用小工具   ·   5525 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 08:37 · PVG 16:37 · LAX 00:37 · JFK 03:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.