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 请求是不是需要/预期有请求正文?的主要内容,如果未能解决你的问题,请参考以下文章