【问题标题】:Is this statement correct? HTTP GET method always has no message body这个说法正确吗? HTTP GET 方法总是没有消息体
【发布时间】:2011-07-10 03:35:00
【问题描述】:

这个说法正确吗? HTTP GET 方法总是没有消息体。 我没有找到 RFC2616 的任何部分明确说明这一点。

如果不是这样,那么在什么情况下 Http GET 请求会包含消息体

【问题讨论】:

标签: http-headers


【解决方案1】:

restclientREST console 都不支持,但 curl 支持。

original HTTP 1.1 specification 在第 4.3 节中说

如果请求方法的规范(第 5.1.1 节)不允许在请求中发送实体主体,则消息主体不得包含在请求中。

Section 5.1.1 将我们重定向到第 9.x 节以了解各种方法。它们都没有明确禁止包含消息体。不过……

Section 5.2

Internet 请求所标识的确切资源是通过检查 Request-URI 和 Host 标头字段来确定的。

Section 9.3

GET 方法意味着检索由 Request-URI 标识的任何信息(以实体的形式)。

这表明在处理 GET 请求时,服务器不需要检查 Request-URI 和 Host 标头字段以外的任何内容。

总而言之,HTTP 规范不会阻止您使用 GET 发送消息正文,但是如果不是所有服务器都支持它,我不会感到惊讶。

【讨论】:

  • 需要注意的是,虽然 HTTP 规范没有明确禁止在 GET 请求中使用正文,但它是没有意义的。 HTTP 也不会阻止你在进行 POST 请求时拍手,但不会影响其操作。
  • 切题到这一点,GET 请求通常是人们可能想要添加书签或复制并粘贴给朋友的东西。在使用请求正文(无论是 GET 还是 POST)实现时,您不能完全做到这一点。在这种情况下,与在达到长度上限时通过 POST 实现相比,将查询参数键名称设置为不那么具有描述性但简洁的名称可能更为谨慎。
  • @evert 我不明白你在说什么。 OP 正在编写一个 REST API... 在 REST 中,这些方法具有以下含义:GET -> 读取/查找/选择,POST -> 创建,PUT -> 更新,DELETE -> 删除。但是,如果您的选择标准太大而无法放入 URL 中怎么办?例如。我想要这个 500 个记录 ID 列表的详细信息...使用 POST 与 REST 中的含义相反...我们要选择数据,而不是创建它。但是 500 个 ID 不适合 URL ......所以这就是欲望的来源。我认为规范表明可以让他的 server 接受 GET 请求的主体。
  • @StijndeWitt 绝对不是,这将是一个糟糕的主意。大多数中间体实际上完全放弃了GET 请求正文。缓存标头也将无法运行,因为结果将取决于请求正文(应忽略)GET 仅用于根据 url 和一组接受标头检索表示。仅此而已。
  • 如果你认为你想要你描述的请求并且你坚持做一个REST服务,你应该创建一个你的条件使用的报告POSTPUT(有点像物化视图)然后获取它的结果。或者您需要重新考虑您的媒体类型和资源。
【解决方案2】:

旧的 RFC2616 已被取代,并被多个 RFC (7230-7237) 取代。

新的RFC 7230 on HTTP/1.1 明确说明了邮件正文:

HTTP 消息的消息体(如果有)用于携带
该请求或响应的有效负载正文。邮件正文是
与有效载荷主体相同,除非传输编码已被
应用,如第 3.3.1 节所述。

 message-body = *OCTET

消息中何时允许消息正文的规则不同 用于请求和响应。

请求中存在消息正文由 a
发出信号 Content-Length 或 Transfer-Encoding 标头字段。 请求消息
框架独立于方法语义
,即使方法确实如此
未定义消息正文的任何​​用途。

所以新标准清楚地回答了最初的问题。但是有一些旧软件会在GET请求中忽略message-body,所以你需要谨慎并检查这种情况。

【讨论】:

  • 您说“清楚”两次,但我不太清楚。我认为您是在说“是否存在正文仅取决于 Content-Length 和/或 Transfer-Encoding 标头的存在”?
【解决方案3】:

我在 elasticsearch 中遇到过这个问题,其中带有消息正文的 GET 请求用于测试分析器 - https://www.elastic.co/guide/en/elasticsearch/guide/master/analysis-intro.html

本质上,这是一个不会更改服务器端任何内容的请求,但它需要将长文本消息作为输入传递。似乎是对带有消息正文的 GET 请求的恰当使用。

【讨论】:

    【解决方案4】:

    认为规范允许您添加消息正文,因此您的问题的答案应该是(但有一些警告)。

    让我们首先检查一下规范(我引用了 RFC 7231RFC 7232RFC 7234,因为其他答案中提到的 RFC 2616 已被他们淘汰)。

    From RFC 7230:

    The presence of a message body in a request is signaled by a
    Content-Length or Transfer-Encoding header field. Request message
    framing is independent of method semantics, even if the method does
    not define any use for a message body.
    

    请注意,部分“如果请求方法的规范(第 5.1.1 节)不允许在请求中发送实体主体,则消息主体不得包含在请求中。” 旧 RFC 2616 中的内容已被删除。

    还有 RFC 7231 says this on the subject:

    A payload within a GET request message has no defined semantics;
    sending a payload body on a GET request might cause some existing
    implementations to reject the request.
    

    因此,在我看来,这意味着您可以向 GET 请求添加消息正文(这应该回答您最初的问题),但您必须小心。规范中提到的案例并不是您必须了解的唯一案例,许多工具、客户端和服务器根本不期望消息正文,并且可能行为不端。例如,在 Chrome 中,XMLHttpRequest 将删除 GET 的消息正文。

    另一个问题是缓存问题。根据RFC 7234.

    The primary cache key consists of the request method and target URI   
    [...]
    If a request target is subject to content negotiation, its cache
    entry might consist of multiple stored responses, each differentiated
    by a secondary key for the values of the original request's selecting
    header fields.
    

    这意味着具有不同正文但相同 url(可能还有选定的标头)的请求将被缓存视为具有相同的响应,即使消息正文之前已正确转发到服务器。

    最后我认为如果可能你应该避免在 GET 中使用消息体,除非

    • 您控制客户端
    • 您控制服务器
    • 您知道潜在的代理、缓存可能会妨碍您
    • 您在响应中禁用了缓存(实际上您可能能够(ab)使用标头来缓存,但我没有正确调查这个想法)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-24
      • 2013-10-28
      • 2015-12-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多