使用 POST 创建请求,响应代码为 200 或 201 和内容
Posted
技术标签:
【中文标题】使用 POST 创建请求,响应代码为 200 或 201 和内容【英文标题】:Create request with POST, which response codes 200 or 201 and content 【发布时间】:2010-12-24 01:21:37 【问题描述】:假设我编写了一个 REST 服务,其目的是向系统添加新数据项。
我打算发帖到
http://myhost/serviceX/someResources
假设可行,我应该使用什么响应代码?我可以返回什么内容。
我正在查看 HTTP 响应代码的 definitions 并看到这些可能性:
200:返回描述或包含动作结果的实体;
201:表示已创建。含义 *请求已完成并导致创建新资源。新创建的资源可以被响应实体中返回的 URI 引用,资源的最具体的 URI 由 Location 头字段给出。响应应该包括一个实体,其中包含资源特征和位置列表,用户或用户代理可以从中选择最合适的一个。实体格式由 Content-Type 标头字段中给出的媒体类型指定。 *
后者听起来更符合 Http 规范,但我完全不清楚是什么
响应应该包含一个实体 包含资源列表 特征和位置
意思。
建议?解释?
【问题讨论】:
【参考方案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://***.com/a/36373586/12597
响应正文
他们接着提到你应该在回复中包含什么body:
201
响应负载通常描述并链接到创建的资源。
对于使用浏览器的人,您可以为他们提供可以查看的内容,然后单击以访问他们新创建的资源:
HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://***.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://***.com/a/36373586/12597
Content-Type: application/xml
<createdResources>
<questionID>1860645</questionID>
<answerID>36373586</answerID>
<primary>/a/36373586/12597</primary>
<additional>
<resource>http://***.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586</resource>
<resource>http://***.com/a/1962757/12597</resource>
</additional>
</createdResource>
或者,如果您愿意:
HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://***.com/a/36373586/12597
Content-Type: application/json
"questionID": 1860645,
"answerID": 36373586,
"primary": "/a/36373586/12597",
"additional": [
"http://***.com/questions/1860645/create-request-with-post-which-response-codes-200-or-201-and-content/36373586#36373586",
"http://***.com/a/36373586/12597"
]
回复完全取决于您;随心所欲。
缓存友好
最后还有一个优化,我可以预先缓存创建的资源(因为我已经有了内容;我刚刚上传了它)。服务器可以返回一个日期或 ETag
,我可以将其与我刚刚上传的内容一起存储:
请参阅Section 7.2,了解
201
响应中验证器标头字段(例如ETag
和Last-Modified
)的含义和用途。
HTTP/1.1 201 Created
Date: Sat, 02 Apr 2016 12:22:40 GMT
Location: http://***.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 或链接)时【讨论】:
这个来源? 这是我从w3.org/Protocols/rfc2616/rfc2616-sec10.html 和httpstatuses.com/201 了解到的 在阅读了tools.ietf.org/html/rfc7231#section-6.3.1 之后,我同意这种理解——我想我更多的是问你是如何得出这个结论的。但现在在我的理解中...... 200 = 创建并返回的资源 | 201 = 创建资源并返回引用 | 204 = 已创建资源但未返回有效负载 @sudosoul 是否也会像在 201 中一样返回带有 204 的位置标头? @MiguelPynto 根据 RFC 7231,我会说不,位置标头不应返回 204。尽管,204 响应可以包含标头元数据,最终暗示请求成功。检查我发布到 RFC 7231 的链接并查看 204 上的段落。以上是关于使用 POST 创建请求,响应代码为 200 或 201 和内容的主要内容,如果未能解决你的问题,请参考以下文章