使用POST创建请求,其响应代码为200或201以及内容


125

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

我打算发布到

http://myhost/serviceX/someResources

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

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

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

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

后者听起来更符合Http规范,但我不清楚

响应应包含一个实体,其中包含资源特征和位置的列表

手段。

建议?解释?

Answers:


77

这个想法是响应主体给您一个页面,该页面将您链接到该事物:

创建了201

状态码201(已创建)表示请求已得到满足,并导致创建了一个或多个新资源。由请求创建的主要资源由响应中的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="https://stackoverflow.com/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,我可以将其与刚刚上传的内容一起存储:

有关201响应中验证头字段(例如ETag和Last-Modified)的含义和目的的讨论,请参见7.2节

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="https://stackoverflow.com/a/36373586/12597">here</A> to view it.

ETags纯粹是任意值。当资源更改(和缓存需要更新)时,让它们有所不同就很重要。ETag通常是一个哈希(例如SHA2)。但是它可以是数据库rowversion,也可以是递增的修订号。当事物改变时,任何会改变事物


到目前为止,您的回应似乎是最明智的。我对响应的本体有点担心,但是除此之外,这似乎是对规范的最成熟的解释。我很好奇是否存在任何轻量级的“响应”方式来处理人机输出。但大多数情况下,我对您的“缓存您自己的输入”建议很感兴趣。我知道的大多数Web应用程序都不会创建该资源的1:1版本。即使这很琐碎,例如将字符串的大小写标准化。将您提交的版本当作创建etag的版本有点难道吗?
安东尼

1
@Anthony,缓存:它可能是一种1:1的文件存储应用程序。比较例如WebDAV PUT&POST。大量文件需要处理。
kxr

@Anthony如果您想将ETag返回给客户端,则取决于您。如果客户端刚刚上传的内容不是您保存的内容,请不要返回ETag。这是您的灵活性和您的选择。
伊恩·博伊德

为什么您的回复缺少内容长度?
文尼·法尔科

1
@VinnieFalco这是有关201响应代码的答案。出于说明目的,已删除了Content-Length。
伊恩·博伊德

91

我认为atompub REST API是宁静服务的一个很好的例子。请参见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发出成功创建的信号。响应包括一个Location头,指示Atom条目的Member Entry URI,以及该条目在响应主体中的表示。

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


9
如果资源的大小为千兆字节,则返回创建的资源可能会有点过多...
Tor Valamo,09年

10
同意!那是对必要性的优化,但是您不希望过早地这样做。重要的是,要以宁静的精神进行设计,并且仅在必要时才进行例外处理。
钱德拉·帕特尼

3
@ ChandraPatni,Atom已死。需要更好的例子。
Pacerier,2015年

16
原子可能已经死了,但是示例的精神仍然存在。
Ashimema

2
我对201响应的原始解释更像是“嘿,您想创建一个资源,但是基于上下文,您要么对最终结果不感兴趣,要么对该资源具有写访问权,但没有读访问权。在这种情况下,返回主集合之前,您所需要的就是所创建资源的URL。作为证据,该资源已创建。” 从本质上讲,超出此限制的任何内容似乎都需要200个响应。除非RFC还有其他想法。
安东尼

50

简单来说:

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

来源吗?
sudo soul


3
在阅读tools.ietf.org/html/rfc7231#section-6.3.1之后,我同意这种理解-我想我是在问更多你是如何到达的。但现在据我了解... 200 =资源已创建并返回| 201 =创建资源并返回引用| 204 =已创建资源且未返回任何有效负载
sudo魂

34

查看HTTP:方法定义:POST

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

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


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


3
您说的是ETag对应于包含资源特征和位置列表实体。我可以看到您的建议很好,非常同意您对测试的观点。但是,我看不出这与“资源特征和位置列表”如何匹配。
djna

“资源特征和位置列表”将是所提供的任何数据结构的内容。对于JSON结构,更严格的实现将包括资源uri以及可能创建的资源类型。我将这样调整答案。
tempire

7
指定问题,以便人们学习。否则,评论只是挥舞一下。
tempire 13-10-21

@SimonGibbs什么问题?
MEMark 2014年

2
虽然严格按照规范是正确的,但建议使用非常不常见的实现选项。此外,它实际上并没有回答页面顶部的问题(或者通过混合单词ETag和Entity来回答)。43票的答案可能更好。
西蒙·吉布斯


-2

我对此的另一个答案是采取务实的方法并使REST API合同保持简单。就我而言,我已经重构了REST API,以使事情更具可测试性,而不必依靠JavaScript或XHR,而只是简单的HTML表单和链接。

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.