PUT 和 POST 请求是不是需要/预期有请求正文?

Posted

技术标签:

【中文标题】PUT 和 POST 请求是不是需要/预期有请求正文?【英文标题】:Are PUT and POST requests required/expected to have a request body?PUT 和 POST 请求是否需要/预期有请求正文? 【发布时间】:2011-11-11 13:03:14 【问题描述】:

我正在编写一个 RESTful api,并且正在考虑用户创建密钥的过程。我有以下几种可能:

GET 请求到/new/<keyname> - 虽然它很简单,但我想我不会使用它,因为我听说 GET 用于检索和/或列出信息; POST 请求到/<keyname> - 在我看来这很容易和简单,但不会在请求正文中传递任何数据。我可以这样做吗?这很奇怪吗? POST 请求到 /keys 传递请求正文 "keyname=SomeKey" - 这是正确的方法吗?

我查看了this API from joyent,在他们所有的 PUT 和 POST 请求中,他们在请求正文中传递了一些数据。这是预期的吗?在 PUT 和 POST 请求中不要求请求正文真的是错误的吗?

【问题讨论】:

【参考方案1】:

我在 Http-WG 上问过这个问题。这是我得到的最准确的答案http://lists.w3.org/Archives/Public/ietf-http-wg/2010JulSep/0276.html

总之,POST 不需要正文。我希望同样的理由可以应用于 PUT。

【讨论】:

POST 确实需要一个正文,但该正文可以是一个空文档。区别很微妙,但不是一回事。例如,您仍然有空文档的 mimetype。 @PedroWerneck 您能否为该断言提供参考?我所读到的内容与这种观点不一致。 这就是您发布的答案所说的。零长度的身体与没有身体不同。您仍然需要发送一些与空文档相关的元数据。 @PedroWerneck ...但我们在谈论 HTTP,不是吗?在您的理解中,如何将没有正文的 HTTP 表示更改为具有空正文的 HTTP 表示? @PedroWerneck 我知道空的 json 文档与 no-body 不同,也与空的 text/plain 文档不同。但这与原始问题无关。我仍然认为没有人的 POST 是有效的。这就是你在上一条评论中所说的。【参考方案2】:

RFC2616 is the base RFC for HTTP 1.1

在最一般的形式中,HTTP 消息是这样的(注意可选的正文):

通用消息 = 起始行
                  *(消息头 CRLF)
                  CRLF
                  [ 邮件正文 ]
start-line = 请求行 |状态行

进一步阅读会得出这样的结论:

9.5 发布

   POST 方法用于请求源服务器接受
   包含在请求中的实体作为资源的新下属
   由 Request-Line 中的 Request-URI 标识。 ...

9.6 放

   PUT 方法请求将封闭的实体存储在
   提供的请求 URI。 ...

   POST 和 PUT 请求之间的根本区别是
   体现在Request-URI的不同含义上。 URI 中的
   POST 请求标识将处理封闭的资源
   实体。该资源可能是一个数据接受过程,一个通往
   一些其他协议,或接受注释的单独实体。
   相反,PUT 请求中的 URI 标识包含的实体
   与请求 - 用户代理知道 URI 的意图和
   服务器不得尝试将请求应用于其他资源。

POST 和 PUT 都包含短语请求中包含的实体

根据我的阅读,我认为 POST 和 PUT 都需要一个主体(我知道,这是一种非规范性描述)。

在 REST 的上下文中,POST 是创建,PUT 是更新。我可以想象创建一个空对象(可能是未来信息的占位符),但我不认为空更新的用途很多。

【讨论】:

“在 REST 的上下文中”是什么意思? REST在哪里重新定义了HTTP POST方法的含义? 一个 REST POST 是一个创建请求。我可以想象我想使用所有默认值(可能由空正文标识)创建由 URL 标识的资源的情况。 POST 不一定是创建请求。 “创建从属资源”只是建议的含义之一。所有关于 POST 的 http 规范都说它是不安全且非幂等的。其余语义未指定。 POST 是用于任何未由 HTTP 标准化的操作的方法。在 CRUD 中使用 POST 作为 CREATE 的同义词是 HTTP API 中的常见约定,但在 REST API 中,POST 可以做任何事情,只要目标媒体类型记录在案。【参考方案3】:

这不是必需的。您可以发送没有正文的 POST/PUT 请求,而是使用查询字符串参数。但要小心,如果您的参数包含非 HTTP 有效的字符,您将不得不对它们进行编码。

例如,如果您需要 POST 'hello world' 到终点,您必须使其看起来像这样:http://api.com?param=hello%20world

【讨论】:

【参考方案4】:

可能最好的方法是您的第三个选项:使用keyname=SomeKey POST 到/keys

原因如下:您可能希望向 API 添加另一个函数,例如 create_new_user。这样就很难区分尝试发布名为create_new_user 的密钥的用户和尝试使用create_new_user 函数的用户。

您说您不应该像 GET 操作"SHOULD NOT have the significance of taking an action other than retrieval." (RFC 2616) 那样使用 GET 来执行此操作是正确的。

【讨论】:

【参考方案5】:

在一行中回答您的问题。是的,预计正文中有正文/内容,但这不是必需的(强制)。

【讨论】:

【参考方案6】:

根据 okHttp3(android 的 HTTP 库):以下方法需要一个主体:POST、PUT、PATCH、PROPPATCH (WebDAV) 和 REPORT (source)。如果您尝试使用没有正文的给定方法发出请求,它甚至会崩溃。

【讨论】:

以上是关于PUT 和 POST 请求是不是需要/预期有请求正文?的主要内容,如果未能解决你的问题,请参考以下文章

HTTP中GET,POST和PUT的区别

delete post put get请求参数

Get、Post、Put

AJAX:POST-PUT-DELETE的问题

java 实现Put request

thinkphp3.2 请求怎么发送 put