代码之家  ›  专栏  ›  技术社区  ›  Panzercrisis

HTTP REST:如果一个请求是幂等的,但一旦插入就不可更改,那么应该使用PUT还是POST?

  •  0
  • Panzercrisis  · 技术社区  · 4 年前

    想象一个HTTP REST端点,其中插入了一个资源,并且该资源被理解为“消息”。每条消息都由一个唯一的标识符标识,例如某种GUID值。 同一消息不能重复。

    现在,在很多情况下,这将有助于 PUT 动词,因为它是幂等的。但是,请考虑以下情况:

    1. The sender sends this message to the receiver:
    
        {
            "id": 123,
            "text": "original text"
        }
    
    2. Now the receiver has this value for the message stored in its database:
    
        {
            "id": 123,
            "text": "original text"
        }
    
    3. For whatever reason, the sender tries to send the same message again, but with amended
       text:
    
        {
            "id": 123,
            "text": "amended text"
        }
    
    4. The receiver receives that as well, but since the id field is the same as before, no
       action is taken, and this is what the receiver still has in its database:
    
        {
            "id": 123,
            "text": "original text"
        }
    

    接收者行为的原因是,每个不同的消息都要由其唯一标识 id 字段,如果另一条消息也发送了相同的消息 身份证件 ,它只是被认为是重复的。此外,尝试更改消息的内容,并使用相同的ID重新发送 无效 发送方端的行为 .

    所以从技术上讲,这是幂等的,通常倾向于 PUT 。但是,在任何情况下都不允许更新,只需插入即可。那么,我们选择 PUT POST ,或者这真的重要吗? PUT 应该是资源的完整表示,但如果它被简单地丢弃,是否仍然可以返回 2xx 回应?

    为了解决这个问题,假设所使用的路由始终为以下形式 <host>/.../message ,从来没有的形式 <host>/.../message/{id} 。在这种情况下,我想知道是否仅限于 <主机>//消息 路线方案自动意味着 职位 应该使用。

    0 回复  |  直到 4 年前
        1
  •  1
  •   kag0    4 年前

    现在,在很多情况下,这将适合POST动词,因为它是幂等的。

    这可能是你端的拼写错误,但是 POST 不是幂等的。然而 PUT 是。

    PUT应该是资源的完整表示,但如果它被简单地丢弃,是否仍然可以返回2xx响应?

    完全好。您请求具有给定id的资源具有给定状态,当返回响应时,这将是真的。

    那么,我们是选择PUT还是POST,或者这真的重要吗?

    我认为好的选择是

    • PUT /messages/{id} ,如果id是新的,则为201,如果消息与现有消息具有相同的文本,则为204,如果文本与现有消息不同,则为4xx
    • POST /messages ,如果id是新的,则为201,如果id已经存在,则为4xx

    随着 PUT 客户端可以看到“哦,2xx,消息已送达”或“4xx,我搞砸了”。但你必须有一些机制(可能是指纹)来快速检查文本是否与初始消息相同。
    随着 职位 客户端需要检查错误响应,看看是否需要修复某些问题并重试,或者消息是否已经送达。如果我们从我们的返回值中返回2xx(不是202) 职位 对于现有消息,大多数客户端会将其解释为发送了新的(重复的)消息。

    假设所使用的路由始终为以下形式 <host>/.../message ,从来没有的形式 <host>/.../message/{id}

    一个不幸的要求,在这种情况下,我会使用 职位 如上所述。从技术上讲,我们可以使用 PUT 使用该路径,但通常这会表明我们想要创建/替换整个消息历史记录(您可以围绕它进行文档记录,但不做看起来应该做的事情的操作通常不会被视为RESTfull)。

        2
  •  1
  •   Community CDub    3 年前

    想象一个HTTP REST端点。。。

    根据菲尔丁本人的说法

    不存在REST端点。有资源。仅受URL长度限制的可数无限资源集。( Source )

    所以从技术上讲,这是幂等的,通常倾向于PUT或PATCH。。。

    Idempotency是客户端在临时网络问题方面的一个重要属性,它允许客户端在合理的时间内没有收到响应的情况下自动重新发送请求。在这种情况下,客户端根本不知道服务器是否收到了初始请求,或者只是丢失了响应。Idempotency与您只允许对资源写入一次的要求无关。除此之外, PATCH 默认情况下不是幂等的。Idempotent只是意味着处理一个请求总是得到相同的结果,无论你向服务器发送了多少次请求。

    每条消息都由一个唯一的标识符标识,例如某种GUID值

    …每条不同的消息都将由其id字段唯一标识,如果另一条消息使用相同的id发送,则只会被视为重复。

    资源总是通过其URI唯一标识的,因为URI本身只能引用一个资源。然而,单个资源可能有多个URI,即一个URI和另一个URI没有可用的查询参数。URI是 统一资源标识符 ,在哪里 制服 表示 在所有情况下和任何时候都保持不变 这就要求 身份证件 在我看来,这个领域是多余的。

    据我所知,消息的实际文本并没有定义消息是否重复。所以基本上

    PUT /messages/eaff31bd-5291-4287-a7dd-fbe5b1e47b67 HTTP/1.1
    Host: www.acme.com
    Content-Type: application/json; charset="utf-8"
    ...
    
    {
      "text": "original text"
    }
    

    PUT /messages/eb1db214-d231-4a50-916c-8de2d64c7d3a HTTP/1.1
    Host: www.acme.com
    Content-Type: application/json; charset="utf-8"
    ...
    
    {
      "text": "original text"
    }
    

    是对两条不同消息的请求,因为它们针对不同的资源,而您不想允许类似

    PUT /messages/eaff31bd-5291-4287-a7dd-fbe5b1e47b67 HTTP/1.1
    Host: www.acme.com
    Content-Type: application/json; charset="utf-8"
    ...
    
    {
      "text": "amended text"
    }
    

    因为这将更新现有消息。

    在这种情况下,我会禁用 PUT 完全用于消息,不支持它,同时只允许通过以下方式创建新消息 POST 请求/响应示例可能如下:

    POST /messages HTTP/1.1
    Host: www.acme.com
    Content-Type: application/json; charset="utf-8"
    Accept: application/json
    ...
    
    {
      "text": "Some other text"
    }
    

    这可能会产生如下响应:

    HTTP/1.1 201 Created
    Content-Type: application/json; charset="utf-8"
    Location: http://www.acme.com/messages/740177d2-1de9-41bd-bd5b-6a52f39bf227
    Etag: 33a64df551425fcc55e4d42a148795d9f25f89d4
    
    {
      "text": "some other text"
    }
    

    尝试通过以下方式更新此类资源

    PUT /messages/740177d2-1de9-41bd-bd5b-6a52f39bf227 HTTP/1.1
    Host: www.acme.com
    Content-Type: application/json; charset="utf-8"
    Etag: 33a64df551425fcc55e4d42a148795d9f25f89d4
    
    {
      "text": "updated text"
    }
    

    应导致

    HTTP/1.1 405 Method Not Allowed
    Allow: GET, HEAD
    

    响应,其中指出 a server knows the indicated PUT operation but does not support that operation on the target resource .强制性 Allow header还向您的客户端说明该资源支持的有效HTTP操作。

    为了解决这个问题,假设使用的路由始终是/…的形式/消息,从来没有形式//消息/{id}。在这种情况下,我想知道是否仅限于//消息路由方案自动意味着应该使用POST。

    在这种情况下 PUT 除非该请求包含处理请求后应可用的所有消息,否则您无法选择。PUT的语义被定义为用请求有效载荷中提供的表示替换存储在目标资源上的当前表示。因此,如果您向“收集资源”发送PUT请求,从技术上讲,您将用请求中定义的消息替换当前可用的所有消息。