169

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

我打算发布到

http://myhost/serviceX/someResources

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

我正在查看 HTTP 响应代码的定义并查看以下可能性:

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

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

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

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

方法。

建议?解释?

4

7 回答 7

116

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

201 已创建

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

这意味着您将Location在响应标头中包含一个,该标头提供您可以找到新创建的东西的 URL :

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

响应正文

然后他们继续提到您应该在响应正文中包含的内容:

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我可以将其与我刚刚上传的内容一起存储:

请参阅第 7.2 节,了解响应中验证器标头字段的含义和用途,例如ETagand 。Last-Modified201

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.

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

于 2016-04-02T12:58:34.657 回答
94

我认为atompub REST API是一个很好的 restful 服务示例。请参阅 atompub 规范中的以下片段:

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 值,并且可以选择删除或添加其他元素和属性,或者更改元素内容和属性值。

于 2009-12-27T05:58:44.117 回答
93

简单来说:

  • 创建返回对象时为200
  • 201创建对象但仅​​返回其引用(例如 ID 或链接)
于 2017-06-06T17:13:41.933 回答
38

查看HTTP:方法定义:POST

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

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

于 2014-05-16T20:45:52.117 回答
18

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和类型是“资源特征和位置”。

于 2009-12-26T06:42:06.310 回答
1

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

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

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

于 2013-05-03T07:20:58.423 回答
-1

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

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

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

于 2014-07-23T14:49:53.717 回答