【问题标题】:Create request with POST, which response codes 200 or 201 and content使用 POST 创建请求,响应代码为 200 或 201 和内容
【发布时间】:2010-12-24 01:21:37
【问题描述】:

假设我编写了一个 REST 服务,其目的是向系统添加新数据项。

我打算发帖到

http://myhost/serviceX/someResources

假设可行,我应该使用什么响应代码?我可以返回什么内容。

我正在查看 HTTP 响应代码的 definitions 并看到这些可能性:

200:返回描述或包含动作结果的实体;

201:表示已创建。含义 *请求已完成并导致创建新资源。新创建的资源可以被响应实体中返回的 URI 引用,资源的最具体的 URI 由 Location 头字段给出。响应应该包括一个实体,其中包含资源特征和位置列表,用户或用户代理可以从中选择最合适的一个。实体格式由 Content-Type 标头字段中给出的媒体类型指定。 *

后者听起来更符合 Http 规范,但我完全不清楚是什么

响应应该包含一个实体 包含资源列表 特征和位置

意思。

建议?解释?

【问题讨论】:

    标签: rest content-type http-status-codes


    【解决方案1】:

    http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19

    这只是一个冒号分隔的键值。

    ETag:“xyzzy”

    它可以是任何类型的文本数据——我通常包含一个带有所创建项目标识符的 JSON 字符串。单独测试的简单性使得包含它是值得的。

    ETag: "{ id: 1234, uri: 'http://domain.com/comments/1234', type: 'comment' }"
    

    在本例中,所创建项目的标识符、uri 和类型是“资源特征和位置”。

    【讨论】:

    • 您是说 ETag 对应于一个包含资源特征和位置列表的实体。我可以看到你的建议很好,非常同意你关于测试的观点。但是,我看不出这与“资源特征和位置列表”有什么关系。
    • “资源特征和位置列表”将是所提供的任何数据结构的内容。更严格的实现是让 JSON 结构包含资源 uri 以及可能创建的资源类型。我会这样调整答案。
    • 指定问题,以便人们学习。否则,评论只是在挥手。
    • @SimonGibbs 有什么问题?
    • 虽然按照规范严格正确,但它推荐了一个非常不寻常的实现选项。此外,它实际上并没有回答页面顶部的问题(或者它通过混合单词 ETag 和实体来回答)。 43 票的答案可能更好。
    【解决方案2】:

    我认为atompub REST API 是宁静服务的一个很好的例子。请参阅 atompub 规范中的以下 sn-p:

    POST /edit/ HTTP/1.1
    Host: example.org
    User-Agent: Thingio/1.0
    Authorization: Basic ZGFmZnk6c2VjZXJldA==
    Content-Type: application/atom+xml;type=entry
    Content-Length: nnn
    Slug: First Post
    
    <?xml version="1.0"?>
    <entry xmlns="http://www.w3.org/2005/Atom">
      <title>Atom-Powered Robots Run Amok</title>
      <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
      <updated>2003-12-13T18:30:02Z</updated>
      <author><name>John Doe</name></author>
      <content>Some text.</content>
    </entry>
    

    服务器使用状态码 201 表示创建成功。响应包括指示 Atom 条目的成员条目 URI 的 Location 标头,以及响应正文中该条目的表示。

    HTTP/1.1 201 Created
    Date: Fri, 7 Oct 2005 17:17:11 GMT
    Content-Length: nnn
    Content-Type: application/atom+xml;type=entry;charset="utf-8"
    Location: http://example.org/edit/first-post.atom
    ETag: "c180de84f991g8"  
    
    <?xml version="1.0"?>
    <entry xmlns="http://www.w3.org/2005/Atom">
      <title>Atom-Powered Robots Run Amok</title>
      <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
      <updated>2003-12-13T18:30:02Z</updated>
      <author><name>John Doe</name></author>
      <content>Some text.</content>
      <link rel="edit"
          href="http://example.org/edit/first-post.atom"/>
    </entry>
    

    集合创建和返回的条目可能与客户端发布的条目不匹配。服务器可以更改条目中各种元素的值,例如 atom:id、atom:updated 和 atom:author 值,并且可以选择删除或添加其他元素和属性,或者更改元素内容和属性值。

    【讨论】:

    • 返回创建的资源可能有点多,如果资源在千兆字节量级...
    • 同意!这是必要性的优化——但你不想过早地这样做。以宁静的精神进行设计并仅在必要时例外处理是很重要的。
    • @ChandraPatni,Atom 死了。需要更好的例子。
    • Atom 可能已经死了,但示例的精神仍然存在。
    • 我对 201 响应的原始解释更像是“嘿,你想创建一个资源,但根据上下文,你要么对最终结果不感兴趣,要么有写权限但没有对此资源的读取访问权限。无论哪种情况,在返回主集合之前,您只需要创建资源的 URL。作为创建资源的证据。”基本上,除此之外的任何内容似乎都是 200 响应。除非 RFC 有其他想法。
    【解决方案3】:

    输出实际上取决于所请求的内容类型。但是,您至少应该将创建的资源放在 Location 中。就像 Post-Redirect-Get 模式一样。

    在我的情况下,除非另有要求,否则我将其留空。因为这是使用 Response.created() 时 JAX-RS 的行为。

    但是,请注意,像 Angular 这样的浏览器和框架不会自动遵循 201。我已经注意到http://www.trajano.net/2013/05/201-created-with-angular-resource/中的行为

    【讨论】:

      【解决方案4】:

      查看HTTP: Method Definitions: POST

      POST 方法执行的操作可能不会产生可以通过 URI 识别的资源。在这种情况下,200(正常)或 204(无内容)是适当的响应状态,具体取决于响应是否包含描述结果的实体。

      如果在源服务器上创建了资源,则响应应该是 201(已创建)并包含描述请求状态并引用新资源的实体,以及 Location 标头(参见第 14.30 节)。

      【讨论】:

        【解决方案5】:

        我对此的另一个答案是采取务实的方法并保持您的REST API contract 简单。在我的例子中,我重构了我的 REST API 以使事情更具可测试性,而无需使用 JavaScript 或 XHR,只需简单的 HTML 表单和链接。

        因此,为了更具体地说明您的上述问题,我将使用返回码 200 并让返回的消息包含您的应用程序可以理解的 JSON 消息。根据您的需要,它可能需要新创建的对象的 ID,以便 Web 应用程序可以在另一个调用中获取数据。

        请注意,在我重构的 API 合同中,POST 响应不应包含任何可缓存的数据,因为 POST 并不是真正可缓存的,因此将其限制为可以使用 GET 请求请求和缓存的 ID。

        【讨论】:

          【解决方案6】:

          这个想法是响应正文为您提供一个链接您到该事物的页面:

          201 创建

          201(已创建)状态代码表示请求已完成,并导致创建了一个或多个新资源。请求创建的主要资源由响应中的 Location 标头字段标识,如果未收到 Location 字段,则由有效请求 URI 标识。

          这意味着您将在响应header中包含一个Location,它提供了您可以找到新创建的事物的URL >:

          HTTP/1.1 201 Created
          Date: Sat, 02 Apr 2016 12:22:40 GMT
          Location: http://stackoverflow.com/a/36373586/12597
          

          响应正文

          他们接着提到你应该在回复中包含什么body

          201 响应负载通常描述并链接到创建的资源。

          对于使用浏览器的人,您可以为他们提供可以查看的内容,然后单击以访问他们新创建的资源:

          HTTP/1.1 201 Created
          Date: Sat, 02 Apr 2016 12:22:40 GMT
          Location: http://stackoverflow.com/a/36373586/12597
          Content-Type: text/html
          
          Your answer has been saved! 
          Click <A href="/a/36373586/12597">here</A> to view it.
          

          如果该页面仅由机器人使用,则将响应设置为计算机可读是有意义的:

          HTTP/1.1 201 Created
          Date: Sat, 02 Apr 2016 12:22:40 GMT
          Location: http://stackoverflow.com/a/36373586/12597
          Content-Type: application/xml
          
          <createdResources>
             <questionID>1860645</questionID>
             <answerID>36373586</answerID>
             <primary>/a/36373586/12597</primary>
             <additional>
                <resource>http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
                <resource>http://stackoverflow.com/a/1962757/12597</resource>
             </additional>
          </createdResource>
          

          或者,如果您愿意:

          HTTP/1.1 201 Created
          Date: Sat, 02 Apr 2016 12:22:40 GMT
          Location: http://stackoverflow.com/a/36373586/12597
          Content-Type: application/json
          
          { 
             "questionID": 1860645, 
             "answerID": 36373586,
             "primary": "/a/36373586/12597",
             "additional": [
                "http://stackoverflow.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
                "http://stackoverflow.com/a/36373586/12597"
             ]
          }
          

          回复完全取决于您;随心所欲。

          缓存友好

          最后还有一个优化,我可以预先缓存创建的资源(因为我已经有了内容;我刚刚上传了它)。服务器可以返回一个日期或 ETag,我可以将其与我刚刚上传的内容一起存储:

          请参阅Section 7.2,了解201 响应中验证器标头字段(例如ETagLast-Modified)的含义和用途。

          HTTP/1.1 201 Created
          Date: Sat, 02 Apr 2016 12:22:40 GMT
          Location: http://stackoverflow.com/a/23704283/12597
          Content-Type: text/html
          ETag: JF2CA53BOMQGU5LTOQQGC3RAMV4GC3LQNRSS4
          Last-Modified: Sat, 02 Apr 2016 12:22:39 GMT 
          
          Your answer has been saved! 
          Click <A href="/a/36373586/12597">here</A> to view it.
          

          ETag 是纯粹的任意值。当资源发生变化(并且缓存需要更新)时,让它们有所不同是最重要的。 ETag 通常是一个散列(例如 SHA2-256)。但它可以是数据库rowversion,或递增的修订号。当事物改变时,任何会改变的东西。

          【讨论】:

          • 到目前为止,您的反应似乎是最明智的。我有点担心响应的本体,但除此之外,它似乎是对规范的最成熟的解释。我很好奇是否有任何轻量级的“响应式”方式来处理人机输出。但主要是我对你的“缓存你自己的输入”的建议很感兴趣。我知道的大多数网络应用程序都不会创建资源的 1:1 版本。即使它像规范化字符串的大写一样微不足道。将您提交的版本视为创建 etag 的版本是不是有点狡猾?
          • @Anthony,缓存:它可能是一种 1:1 文件存储应用程序。比较例如WebDAV PUT & POST。需要处理的大文件。
          • @Anthony 是否要将 ETag 返回给客户端取决于您。如果客户端刚刚上传的内容不是你保存的,那么不要返回ETag。这是您的灵活性和您的选择。
          • 为什么您的回复缺少 Content-Length?
          • @VinnieFalco 这是关于 201 响应代码的答案。出于说明目的,已省略 Content-Length。
          【解决方案7】:

          简而言之:

          • 200 创建对象时返回
          • 201 当对象被创建但只返回其引用(例如 ID 或链接)时

          【讨论】:

          • 这个来源?
          • 在阅读了tools.ietf.org/html/rfc7231#section-6.3.1 之后,我同意这种理解——我想我更多的是问你是如何得出这个结论的。但现在在我的理解中...... 200 = 创建并返回的资源 | 201 = 创建资源并返回引用 | 204 = 已创建资源但未返回有效负载
          • @sudosoul 是否也会像在 201 中一样返回带有 204 的位置标头?
          • @MiguelPynto 根据 RFC 7231,我会说不,位置标头不应返回 204。尽管,204 响应可以包含标头元数据,最终暗示请求成功。检查我发布到 RFC 7231 的链接并查看 204 上的段落。
          猜你喜欢
          • 1970-01-01
          • 2014-07-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-12
          • 1970-01-01
          相关资源
          最近更新 更多