带请求正文的HTTP GET

Evert 1896 rest http http-get

我正在为我们的应用程序开发一个新的RESTful Web服务.

在某些实体上执行GET时,客户端可以请求实体的内容.如果他们想要添加一些参数(例如排序列表),他们可以在查询字符串中添加这些参数.

或者,我希望人们能够在请求正文中指定这些参数. HTTP/1.1似乎没有明确禁止这一点.这将允许他们指定更多信息,可以更容易指定复杂的XML请求.

我的问题:

  • 这完全是一个好主意吗?
  • HTTP客户端在GET请求中使用请求主体会有问题吗?

http://tools.ietf.org/html/rfc2616

Paul Morgan.. 1578

罗伊菲尔丁关于将一个机构纳入GET请求的评论.

是.换句话说,任何HTTP请求消息都允许包含消息体,因此必须解析消息.但是,GET的服务器语义受到限制,使得正文(如果有的话)对请求没有语义含义.解析的要求与方法语义的要求是分开的.

所以,是的,你可以使用GET发送一个正文,不,这样做永远不会有用.

这是HTTP/1.1的分层设计的一部分,一旦规范被分区(正在进行中),它​​将再次变得清晰.

罗伊....

是的,您可以使用GET发送请求正文,但它不应该有任何意义.如果你通过在服务器上解析它并根据其内容更改响应来赋予它意义,那么你忽略了HTTP/1.1规范第4.3节这个建议:

[...]如果请求方法不包含实体主体的定义语义,那么在处理请求时应该忽略消息体.

HTTP/1.1规范中的GET方法的描述,第9.3节:

GET方法意味着检索Request-URI标识的任何信息([...]).

其中声明请求主体不是GET请求中资源标识的一部分,只是请求URI.

更新 引用为"HTTP/1.1规范"的RFC2616现已过时.2014年,它被RFC 7230-7237取代.引用"处理请求时应该忽略消息体"已被删除.它现在只是"请求消息框架独立于方法语义,即使该方法没有定义消息体的任何用途"第二个引用"GET方法意味着检索任何信息......由Request-URI标识"被删除了. - 来自评论

  • 引用为"HTTP/1.1规范"的RFC2616现已过时.2014年,它被RFC 7230-7237取代.引用"_在处理request_时应该忽略消息体"已被[删除](https://tools.ietf.org/html/rfc7230#section-3.3).它现在只是"_Request消息框架独立于方法语义,即使该方法没有定义消息体的任何用途_"第二个引用"_GET方法意味着检索任何信息......由Request-URI_标识"被删除了(https://tools.ietf.org/html/rfc7231#section-4.3.1).所以,我建议编辑@Jarl的答案 (98认同)
  • Elasticsearch是一个在GET中使用HTTP请求主体的相当重要的产品.根据他们的手册,HTTP请求是否应该支持拥有正文是未定义的.我个人对填充GET请求机构感到不舒服,但他们似乎有不同的意见,他们必须知道他们在做什么.https://www.elastic.co/guide/en/elasticsearch/guide/current/_empty_search.html (94认同)
  • 缓存/代理是你最容易破解的两件事,是的."语义学"只是另一种说法"制造其他组件的人希望其他组件能够运作的方式".如果你违反了语义,那么你更有可能看到人们在写那些期望你尊重那些语义的东西的地方出现问题. (68认同)
  • 我知道这是一个老线程 - 我偶然发现它.@Artem Nakonechny在技术上是正确的,但[新规范](https://tools.ietf.org/html/rfc7231#section-4.3.1)说*"GET请求消息中的有效负载没有定义的语义;发送一个GET请求中的有效负载主体可能会导致某些现有实现拒绝该请求."*因此,如果可以避免,它仍然不是一个好主意. (24认同)
  • @iwein给GET请求机构的意思实际上*不违反规范.[HTTP/1.1](https://tools.ietf.org/html/rfc2616#section-4.3)指定服务器应该忽略主体,但[RFC 2119](https://www.ietf.org/rfc/ rfc2119.txt)指定如果实施者有充分的理由可以忽略"应该"的条款.相反,如果客户*假定更改GET主体*不*更改响应,则*会违反规范. (22认同)
  • 哪个服务器会忽略它? (11认同)
  • 当服务器默默地忽略正文或请求的任何部分时,它会让人头疼.它要么解析它,要么以某种方式抱怨它. (8认同)
  • @GordonM唉,显然他们没有.这个答案是正确的,它违反了GET请求的语义,以根据请求体中的任何数据返回响应. (4认同)
  • PostMan最近还开始允许GET在体内进行测试。 (4认同)
  • Fastcatch是正确的,@ Artem Nakonechny即使您在技术上是正确的,也可以阅读[RFC7231](https://tools.ietf.org/html/rfc7231#section-4.3.1)并说:**发送有效载荷主体GET请求上的内容可能会导致某些现有实现拒绝该请求** (3认同)

caskey.. 273

虽然你可以这样做,但是在HTTP规范没有明确排除的范围内,我建议避免使用它只是因为人们不希望事情以这种方式工作.HTTP请求链中有许多阶段,虽然它们"大部分"符合HTTP规范,但您唯一可以肯定的是它们的行为与Web浏览器一样.(我在想透明代理,加速器,A/V工具包等等)

这就是" 稳健性原则 " 背后的精神,大致是"你接受的是自由的,你所发送的是保守的",你不想在没有充分理由的情况下突破规范的界限.

但是,如果你有充分的理由,那就去吧.

  • 鲁棒性原则存在缺陷.如果你对自己所接受的内容很自由,那么如果你在领养方面取得任何成功,你就会得到废话,只因为你接受废话.这将使您更难以发展您的界面.只看HTML.这是行动中的反叛原则. (213认同)
  • 你有没有试过解析真正的HTML?自己实现它是不可行的,这就是为什么几乎每个人 - 包括像谷歌(Chrome)和苹果(Safari)这样的真正大玩家都没有这样做,而是依靠现有的实现(最终他们都依赖于KDE的KHTML).重用当然很好,但你尝试在.net应用程序中显示html吗?这是一场噩梦,因为你要么必须嵌入一个 - 非托管的 - IE(或类似的)组件,它的问题和崩溃,要么你使用可用的(在codeplex上)托管组件甚至不允许你选择文本. (35认同)
  • 我认为协议的采用(和滥用)的成功和广度说明了鲁棒性原则的价值. (27认同)
  • HTTP规范不仅允许使用GET请求的正文数据,而且这也是常见做法:流行的ElasticSearch引擎的_search API建议使用JSON正文中附加的查询进行GET请求.作为对不完整HTTP客户端实现的让步,它还允许POST请求. (5认同)
  • @ChristianPietsch,这是今天的常见做法.四年前它没有.虽然规范明确允许客户端可选地在请求中包含(MAY)实体(第7节),但是MAY的含义在RFC2119中定义,并且(糟糕的)代理服务器可以符合规范,同时剥离GET请求中的实体,特别是只要它不崩溃,它就可以通过转发请求头而不是包含的实体来提供"减少功能".同样地,关于在不同协议级别之间进行代理时必须/可能/应该进行的版本更改有许多规则. (3认同)
  • @ user437899如果您尝试发送带有GET请求的正文,.NET Framework将抛出异常. (2认同)

Darrel Mille.. 140

如果您尝试利用缓存,则可能会遇到问题.代理人不会在GET主体中查看参数是否会对响应产生影响.

  • 使用ETag/Last-Modified标头字段以这种方式提供帮助:当使用"条件GET"时,代理/缓存可以对此信息起作用. (9认同)
  • @jldupont缓存使用验证器的存在来了解是否可以重新验证过时响应,但是,它们不会用作主缓存密钥或辅助缓存密钥的一部分. (2认同)

Dave Durbin.. 69

restclientREST控制台都不支持这个,但卷曲确实如此.

HTTP规范说,在第4.3节

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

第5.1.1节将我们重定向到第9.x节的各种方法.他们都没有明确禁止包含消息体.然而...

第5.2节

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

9.3节

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

这一点一起表明,在处理GET请求时,服务器不需要检查Request-URI和Host头字段之外的任何其他内容.

总之,HTTP规范并不会阻止您使用GET发送消息体,但是如果所有服务器都不支持它,那么它就不会让我感到惊讶.

  • Paw还可以选择支持机构的GET请求,但必须在设置中启用它. (2认同)

jlecour.. 48

Elasticsearch接受带有正文的GET请求.这似乎是首选方式:http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/common-options.html#_request_body_in_query_string

某些客户端库(如Ruby驱动程序)可以在开发模式下将cry命令记录到stdout,并且它正在广泛使用此语法.

  • 复杂查询可以达到http标头最大长度. (37认同)
  • 它正在阅读弹性搜索文档,它带我到这个问题,因为我认为包含一个正文被认为是不好的做法 (9认同)
  • Elasticsearch使用POST支持相同的请求.他们只选择允许GET中的正文,因为他们认为在查询数据时GET在语义上比POST更正确.有趣的是Elasticsearch在这个帖子中被提到了这么多.我不会用一个例子(虽然来自一个受欢迎的产品)作为遵循这种做法的理由. (8认同)
  • 想知道为什么Elasticsearch允许这样做.这意味着此查询将所有带有效负载的文档计数到GET请求`curl -XGET'http:// localhost:9200/_count?pretty'-d'{"query":{"match_all":{}}}'`相当于将有效负载包括为`source` param:`curl -XGET'http:// localhost:9200/_count?pretty&source =%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D% 7D%7D'` (3认同)

SerialSeb.. 30

您尝试实现的目标已经使用更常见的方法完成了很长时间,并且不依赖于使用GET的有效负载.

您可以简单地构建特定的搜索媒体类型,或者如果您想要更加RESTful,请使用类似OpenSearch的内容,并将请求POST到服务器指示的URI,比如/ search.然后,服务器可以生成搜索结果或构建最终URI并使用303重定向.

这具有遵循传统PRG方法的优点,有助于缓存中介缓存结果等.

也就是说,无论如何,URI都会被编码为非ASCII的任何东西,application/x-www-form-urlencoded和multipart/form-data也是如此.如果您的目的是支持ReSTful场景,我建议使用此而不是创建另一种自定义json格式.

  • 这很聪明,但过于复杂,效率低下.现在你必须发送一个包含你的搜索条件的POST,从你的POST获得一个URI作为回复,然后将带有搜索条件URI的GET发送到服务器,以便获得标准并将结果发回给你.(除了在URI中包含URI在技术上是不可能的,因为你不能在不超过255个字符的内容中发送最多255个字符的内容 - 所以你必须使用部分标识符和服务器然后需要知道如何解析POSTed搜索条件的URI.) (14认同)
  • *您可以简单地构建您的特定搜索媒体类型*您能详细说明吗? (3认同)
  • 我说你可以创建一个名为application/vnd.myCompany.search + json的媒体类型,其中包含您希望客户端发出的搜索模板类型,然后客户端可以将其作为POST发送.正如我所强调的那样,已经存在一种媒体类型,它被称为OpenSearch,当您可以使用现有标准实现场景时,应该在自定义路由上重用现有媒体类型. (2认同)

fijiaaron.. 22

你可以发送一个GET与一个正文或发送一个POST并放弃RESTish宗教信仰(它不是那么糟糕,5年前只有一个信仰成员 - 他的评论在上面联系).

也不是很好的决定,但发送GET机构可能会阻止某些客户端和某些服务器出现问题.

执行POST可能会遇到一些RESTish框架的障碍.

Julian Reschke建议使用像"SEARCH"这样的非标准HTTP标头,这可能是一个优雅的解决方案,除了它更不可能得到支持.

列出能够和不能完成上述各项操作的客户可能是最有效的.

无法通过身体发送GET的客户(我知道):

  • XmlHTTPRequest Fiddler

可以使用正文发送GET的客户端:

  • 大多数浏览器

可以从GET检索正文的服务器和库:

  • 阿帕奇
  • PHP

从GET中剥离主体的服务器(和代理):

  • 当Content-Length为0或未设置时,Squid 3.1.6也会剥离GET主体,否则即使设置了长度,也会发回HTTP 411 Length (2认同)
  • 提琴手会,但它警告你. (2认同)

小智.. 22

哪个服务器会忽略它? - fijiaaron 2012年8月30日21:27

例如Google比忽略它更糟糕,它会认为这是一个错误!

使用简单的netcat自己尝试:

$ netcat www.google.com 80
GET / HTTP/1.1
Host: www.google.com
Content-length: 6

1234

(1234内容后跟CR-LF,所以总共6个字节)

你会得到:

HTTP/1.1 400 Bad Request
Server: GFE/2.0
(....)
Error 400 (Bad Request)
400. That’s an error.
Your client has issued a malformed or illegal request. That’s all we know.

您还可以从Bing,Apple等获得400 Bad Request,这是由AkamaiGhost提供的.

所以我不建议将GET请求与body实体一起使用.

  • 这个例子毫无意义,因为通常当人们要为`GET`请求添加body时,这是因为他们自己的自定义服务器能够处理它.因此,问题是其他"移动部件"(浏览器,缓存等)是否能够正常工作. (59认同)
  • 这是一个糟糕的请求,因为对于特定端点上的'GET`*,您的有效负载不是预期的(或合理的)* - 它与在一般情况下使用`GET`无关.如果内容不是在特定请求的上下文中有意义的格式,则随机有效负载可以轻松地破坏"POST"并返回相同的"400 Bad Request". (4认同)

izrik.. 17

RFC 2616,第4.3节 "消息正文":

服务器应该在任何请求上读取和转发消息体; 如果请求方法不包含实体主体的定义语义,那么在处理请求时应该忽略消息主体.

也就是说,服务器应始终从网络中读取任何提供的请求主体(检查Content-Length或读取分块的主体等).此外,代理应转发他们收到的任何此类请求正文.然后,如果RFC为给定方法定义了主体的语义,则服务器实际上可以使用请求主体来生成响应.但是,如果RFC 没有为正文定义语义,那么服务器应该忽略它.

这符合上面Fielding的引用.

第9.3节 "GET"描述了GET方法的语义,并没有提到请求体.因此,服务器应该忽略它在GET请求上收到的任何请求主体.

  • @CarLuva POST部分说"POST方法用于请求原始服务器接受所附的实体......"[实体主体](http://www.w3.org/Protocols/rfc2616/rfc2616-sec7. html#sec7.2)部分说"实体 - 主体是从消息体中获取的......"因此,POST部分确实提到了消息体,尽管间接地通过引用由消息体携带的实体体来实现. POST请求. (9认同)

小智.. 17

我把这个问题提交给了IETF HTTP WG.Roy Fielding的评论(1998年http/1.1文件的作者)就是这样

"......除了解析和丢弃该机构以外,还可以执行任何其他操作"

RFC 7213(HTTPbis)声明:

"GET请求消息中的有效负载没有定义的语义;"

现在似乎很清楚,目的是禁止GET请求体上的语义,这意味着请求体不能用于影响结果.

如果你在GET上包含一个正文,那里有代理肯定会以各种方式破坏你的请求.

总而言之,不要这样做.


小智.. 8

根据XMLHttpRequest,它无效.从标准:

4.5.6 send()方法

client . send([body = null])

发起请求.可选参数提供请求正文.如果请求方法是GET或,则忽略该参数HEAD.

InvalidStateError如果未打开任何状态或send()设置了标志,则引发异常 .

该方法必须运行以下步骤:send(body)

  1. 如果未打开状态,则抛出InvalidStateError异常.
  2. 如果send()设置了标志,则抛出InvalidStateError异常.
  3. 如果请求方法是GETHEAD,则将body设置为null.
  4. 如果body为null,请转到下一步.

虽然,我认为不应该因为GET请求可能需要大量的内容.

因此,如果您依赖浏览器的XMLHttpRequest,它很可能无法正常工作.

  • 上面的Downvote是错误的,如果某些实现不支持发送具有GET的主体,那么这可能是不执行它的原因,而不管规范如何.我实际上在我正在处理的跨平台产品中遇到了这个问题 - 只有使用XMLHttpRequest的平台无法发送get. (8认同)

gertas.. 7

如果您真的想要将可缓存的JSON/XML主体发送到Web应用程序,那么放置数据的唯一合理位置是使用RFC4648编码的查询字符串:Base 64 Encoding with URL and Filename Safe Alphabet.当然你可以只是urlencode JSON并将put放在URL param的值中,但Base64会给出较小的结果.请记住,有URL大小限制,请参阅不同浏览器中URL的最大长度是多少?.

您可能认为Base64的填充=字符可能对URL的param值不利,但似乎没有 - 请参阅此讨论:http://mail.python.org/pipermail/python-bugs-list/2007-February/037195.html.但是,您不应该将编码数据放在没有参数名称的情况下,因为带有填充的编码字符串将被解释为具有空值的参数键.我会用类似的东西?_b64=<encodeddata>.


cloudhead.. 5

我不建议这样做,这违反了标准做法,并且没有提供太多回报。您想保留正文,而不是选项。


归档时间:

查看次数:

979291 次

最近记录:

8 月 前