带请求正文的HTTP GET


2108

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

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

另外,我希望人们能够在请求正文中指定这些参数。 HTTP / 1.1似乎没有明确禁止这样做。这将使他们能够指定更多信息,可能使指定复杂的XML请求更加容易。

我的问题:

  • 这是个好主意吗?
  • HTTP客户端在GET请求中使用请求主体时会遇到问题吗?

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


552
优点是可以轻松发送XML或JSON请求正文,它没有长度限制,并且更易于编码(UTF-8)。
埃弗特

29
如果您追求的是允许请求正文的安全且幂等的方法,则可能需要查看SEARCH,PROPFIND和REPORT。当然,不使用GET并拥有请求正文会或多或少地使缓存失败。
朱利安·雷施克

226
@fijiaaron:已经三年了,从那时起,我在编写Web服务方面有了丰富的经验。这基本上是我最近几年一直在做的事情。我可以肯定地说,在GET请求中添加主体确实是一个非常糟糕的主意。前两个答案犹如磐石。
埃弗特

26
@Ellesedil:简而言之:由于HTTP的设计方式,使用GET而不是POST所具有的优势。当您以这种方式违反标准时,这些优点将不复存在。因此,使用GET +请求正文而不是POST的理由只有一个:美学。不要为了美观而牺牲坚固的设计。
埃弗特

7
要强调Evert所说的话:“它没有长度限制”。如果您的带有查询参数的GET违反了长度限制(为2048),那么除了将查询字符串信息放入json对象(例如,请求的正文)之外,还有什么其他选择。
基兰·瑞安

Answers:


1724

罗伊·菲尔丁(Roy Fielding)的评论,其中包括一个带有GET请求的物体

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

因此,是的,您可以使用GET发送正文,否,这样做永远没有用。

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

....罗伊

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

[...]如果请求方法不包括用于一个实体主体定义的语义,则该消息体应该被处理请求时忽略。

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

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

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

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


71
缓存/代理是您最有可能打破的两件事,是的。“语义学”只是“制造其他组件的人期望其他组件运行的方式”的另一种表达方式。如果您违反了语义,您很可能会在人们写出希望您尊重这些语义的东西的地方看到事情破裂。
斯图尔特·本特利

108
Elasticsearch是一个相当主要的产品,它在GET中利用HTTP请求主体。根据他们的手册,HTTP请求是否应该支持具有主体是不确定的。我个人对填充GET请求正文不满意,但是他们似乎有不同的意见,他们必须知道自己在做什么。 elastic.co/guide/en/elasticsearch/guide/current/...
GordonM

25
@iwein赋予GET请求主体的含义实际上并不违反规范。HTTP / 1.1指定服务器应该忽略主体,但是RFC 2119指定允许实施者有充分理由忽略“ SHOULD”子句。相反,如果客户端假定更改GET正文不会更改响应,则确实违反了规范。
埃米尔·隆德伯格

107
RFC2616被称为“ HTTP / 1.1规范”,现在已过时。在2014年,它被RFC 7230-7237取代。引用“ 已删除消息正文,在处理请求时应将其忽略 ” 。现在只是“ 请求消息框架与方法语义无关,即使该方法未定义消息主体的任何用法 ”第二个引号“ GET方法意味着检索任何信息……由Request-URI标识 ”已被删除。因此,我建议编辑答案@Jarl
Artem Nakonechny16年

28
我知道这是一个旧线程-我偶然发现了它。@Artem Nakonechny在技术上是正确的,但是新规范说:“ GET请求消息中的有效载荷没有定义的语义;在GET请求上发送有效载荷主体可能会导致某些现有的实现拒绝该请求。” 因此,如果可以避免的话,这仍然不是一个好主意。
fastcatch

289

尽管可以做到这一点,但在HTTP规范未明确禁止的范围内,我建议避免这样做仅是因为人们不希望事情以这种方式起作用。HTTP请求链中有很多阶段,尽管它们“大部分”都符合HTTP规范,但您唯一可以确定的是它们的行为将与Web浏览器的传统用法相同。(我正在考虑透明代理,加速器,A / V工具包等)

这是“ 健壮性原则 ” 背后的精神,即“在接受的内容上是自由的,在发送的内容上是保守的”,您不想在没有充分理由的情况下突破规范的界限。

但是,如果您有充分的理由,那就去吧。


228
健壮性原则是有缺陷的。如果您对所接受的东西持开放态度,那么,如果您在接受方面取得任何成功,就会因为您接受废话而感到沮丧。这将使您更难以开发界面。只要看看HTML。这就是行动中的强力原则。
尤金·别列索夫斯基

27
我认为协议的成功和广泛采用(和滥用)说明了健壮性原则的价值。
卡斯基

39
您是否曾经尝试解析真实的HTML?自己实现它是不可行的,这就是为什么几乎每个人(包括像Google(Chrome)和Apple(Safari)这样的真正大公司)都没有这样做,而是依靠现有的实现(最终他们都依赖KDE的KHTML)的原因。这种重用当然很好,但是您是否尝试过在.net应用程序中显示html?这是一场噩梦,因为您要么必须嵌入一个非托管的IE(或类似)组件(及其问题和崩溃),要么使用一个可用的(在Codeplex上)托管的组件,该组件甚至不允许您选择文本。
尤金·别列索夫斯基

6
HTTP规范不仅允许带有GET请求的正文数据,而且这也是常见的做法:流行的ElasticSearch引擎的_search API推荐带有附加在JSON正文中的查询的GET请求。作为不完整的HTTP客户端实现的一种让步,它还允许此处的POST请求。
Christian Pietsch 2013年

3
@ChristianPietsch,这是今天的常规做法。四年前不是。虽然规范明确允许客户端在请求中包括(MAY)实体(第7节),但MAY的含义在RFC2119中定义,并且(cr脚的)代理服务器在剥离GET请求中的实体时可能符合规范,特别是只要它不会崩溃,它就可以通过转发请求标头而不是所包含的实体来提供“精简功能”。同样,关于在不同协议级别之间进行代理时,必须进行哪些版本更改也有很多规则。
卡斯基

151

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


10
使用ETag / Last-Modified头字段以这种方式提供帮助:当使用“条件GET”时,代理/缓存可以对该信息起作用。
jldupont 2010年

2
@jldupont缓存使用验证器的存在来知道是否可以重新验证过时的响应,但是,它们不用作主缓存键或辅助缓存键的一部分。
Darrel Miller

您可以在查询参数中使用正文的校验和来解决该问题
Adrian May

73

restclientREST控制台都不支持此功能,但是curl支持。

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发送消息正文,但是有足够的歧义,如果不是所有服务器都支持的话,它也不会令我感到惊讶。


2
Paw还可以选择支持带有正文的GET请求,但必须在设置中启用它。
丹尼尔(S.Daniel)

“ GET方法意味着检索由Request-URI标识的任何信息(以实体的形式)。” 那么,获取所有实体的GET端点在技术上是否非法/错误?例如,GET /contacts/100/addresses返回具有的人的地址集合id=100
Josh M.

确保测试REST API的Java库不支持带有主体的GET请求。Apache HttpClient也不支持它。
Paulo Merson

Django还支持解析GET正文
Bruno Finger

60

Elasticsearch接受带有主体的GET请求。甚至似乎这是首选方式:Elasticsearch指南

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


5
想知道为什么Elasticsearch允许这样做。这意味着此查询将所有带有有效负载的文档计数到GET请求 curl -XGET 'http://localhost:9200/_count?pretty' -d ' { "query": { "match_all": {} } }' 中等同于将有效负载作为source参数包括在内: curl -XGET 'http://localhost:9200/_count?pretty&source=%7B%22query%22%3A%7B%22match_all%22%3A%7B%7D%7D%7D'
2014年

39
复杂的查询可以达到http标头的最大长度。
s。丹尼尔(Daniel)

11
正在阅读Elasticsearch文档,使我想到了这个问题,因为我认为包括尸体被认为是不好的做法
PatrickWalker,2016年

1
它甚至不需要是一个复杂的查询。即使是简单的滚动,也可以返回非常长的scroll_id(在具有许多分片的群集中),如果在其中添加,则会导致超出最大URL长度。
布伦特·赫尼克

11
Elasticsearch使用POST支持相同的请求。他们之所以选择允许在GET中使用正文,是因为他们认为GET在查询数据方面比POST在语义上更正确。有趣的是,Elasticsearch在该线程中被提及很多。我不会使用一个示例(尽管来自流行产品)作为遵循该实践的理由。
DSO

32

您试图实现的目标已经用一种更为通用的方法完成了很长时间,并且该方法不依赖于在GET中使用有效负载。

您可以简单地构建您特定的搜索媒体类型,或者如果您想要更RESTful,请使用诸如OpenSearch之类的东西,然后将请求发布到服务器指示的URI,例如/ search。然后,服务器可以生成搜索结果或构建最终URI,并使用303进行重定向。

这具有遵循传统PRG方法的优势,有助于缓存中间人缓存结果等。

也就是说,无论如何,URI都是针对非ASCII的内容进行编码的,因此application / x-www-form-urlencoded和multipart / form-data也是如此。如果您打算支持ReSTful场景,我建议使用此方法,而不是创建另一种自定义json格式。


4
您可以简单地建立您的特定搜索媒体类型,您能否详细说明?
Piotr Dobrogost 2011年

2
那时我说的是,您可以创建一个名为application / vnd.myCompany.search + json的媒体类型,该媒体类型将包含您希望客户端发出的搜索模板,然后客户端可以将其作为POST发送。正如我所强调的那样,已经有一种媒体类型称为OpenSearch,当可以使用现有标准实现方案时,应在自定义路由上选择重用现有媒体类型。
SerialSeb

14
这很聪明,但过于复杂且效率低下。现在,您必须发送包含搜索条件的POST,从POST中获取一个URI作为响应,然后将包含搜索条件URI的GET发送到服务器,以获取GET条件并将结果发送回给您。(除了在技术上不可能在URI中包含URI,因为您不能在不超过255个字符的范围内发送不超过255个字符的邮件-因此,您必须使用部分标识符,然后才能使用服务器需要知道如何为您发布的搜索条件解析URI。)
fijiaaron 2012年

29

您可以发送带有主体的GET或发送POST并放弃RESTish宗教信仰(这还不错,五年前,只有一种信仰的人-他的评论在上面链接)。

好的决定都不是,但是发送GET正文可能会防止某些客户端和某些服务器出现问题。

在某些RESTish框架中进行POST可能会遇到障碍。

朱利安·雷施克(Julian Reschke)上面建议使用非标准的HTTP标头(例如“ SEARCH”),这可能是一个很好的解决方案,只是它受到支持的可能性更低。

列出可以完成上述每一项工作的客户端可能最有效率。

无法发送带有主体的GET的客户端(我知道):

  • XmlHTTPRequest提琴手

可以发送带有正文的GET的客户端:

  • 大多数浏览器

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

  • 阿帕奇
  • 的PHP

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


2
当Content-Length设置为0或未设置时,squid 3.1.6也会剥离GET正文,否则即使设置了长度也发送回HTTP 411 Length Required
rkok,2014年

2
提琴手会的,但是会警告你。
toddmo

您是说一种SEARCH方法可能会一路破坏吗?如果代理不理解方法,那么他们应该按原样通过它,所以我不太确定为什么您认为它会破坏任何东西……
Alexis Wilke

22

我将这个问题提交给IETF HTTP WG。罗伊·菲尔丁(Roy Fielding,1998年http / 1.1文件的作者)的评论是,

“ ...实现会被破坏,无法执行任何其他操作,除非解析并丢弃该正文”

RFC 7213(HTTPbis)指出:

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

现在看来很清楚,其意图是禁止GET请求主体上的语义,这意味着不能使用请求主体来影响结果。

如果在GET上包含正文,肯定有多种代理会以各种方式中断您的请求。

因此,总而言之,不要这样做。


21

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

例如,谷歌比忽略它做得更糟,它将认为这是一个错误

使用简单的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错误请求,这些请求由AkamaiGhost提供。

因此,我不建议将GET请求与主体实体一起使用。


64
这个例子没有意义,因为通常当人们要向GET请求添加主体时,是因为他们自己的自定义服务器能够处理它。因此,问题在于其他“移动部件”(浏览器,缓存等)是否将正常运行。
Pacerier '16

5
这是一个不好的请求,因为GET 在该特定终结点上不希望(或明智)您的有效负载-与GET一般情况下的使用无关。如果内容的格式在特定请求的上下文中不合理,则随机有效载荷可能会POST轻易中断并返回相同400 Bad Request的内容。
nobar

不仅整个端点上,而且在特定的URL上
劳伦斯·多尔

1
这无关紧要,因为它只是该URL上Google的服务器实现。因此,这个问题毫无意义
Joel Duckworth

对我来说,这很有用,因为我试图将Firebase函数与get request + body一起使用,并且此错误可能非常隐蔽并且难以理解。
scrimau

19

根据RFC 2616第4.3节 “消息正文”:

服务器应根据任何请求读取并转发消息正文;如果请求方法不包含为实体主体定义的语义,则在处理请求时应忽略消息主体。

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

这与上面Fielding的报价一致。

第9.3节 “ GET”描述了GET方法的语义,没有提及请求主体。因此,服务器应忽略它在GET请求上收到的任何请求正文。


9.5节 “ POST”也没有提到请求正文,因此此逻辑有缺陷。
CarLuva 2014年

9
@CarLuva POST部分显示“ POST方法用于请求源服务器接受包含的实体...” 实体主体部分显示“实体实体是从消息主体获取的……”因此, POST部分确实提到了消息主体,尽管间接引用了POST请求消息主体所携带的实体主体。
frederickf 2014年

9

根据XMLHttpRequest,它是无效的。从标准

4.5.6 send()方法

client . send([body = null])

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

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

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

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

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

因此,如果您依赖浏览器的XMLHttpRequest,则可能无法使用。


1
由于XMLHttpRequest是一个实现而被否决。它可能无法反映应实现的实际规范。
floum

10
上面的向下投票是错误的,如果某些实现不支持发送带有GET的正文,那么这可能是不这样做的原因,而与规范无关。我实际上在我正在开发的跨平台产品中遇到了这个确切的问题-只有使用XMLHttpRequest的平台无法发送get。
pjcard

8

如果您确实想将可缓存的JSON / XML正文发送到Web应用程序,则放置数据的唯一合理位置是使用RFC4648编码的查询字符串:使用URL和Filename Safe Alphabet的Base 64编码。当然,您可以使用urlencode JSON并将其放在URL参数的值中,但是Base64给出的结果较小。请记住,存在URL大小限制,请参阅不同浏览器中URL的最大长度是多少?

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


我认为这是一个非常糟糕的主意:)但是,如果要执行类似的操作,我将改用自定义HTTP标头(并确保在响应中始终发回Vary :)。
Evert 2013年

不好或不行,但可行:)头中的数据存在类似的数据大小问题,请参见stackoverflow.com/questions/686217/…。但是,感谢您提及Vary标头,我并不知道它的真正潜力。
gertas

6

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


5

不符合标准的base64编码标头呢?“ SOMETHINGAPP-PARAMS:sdfSD45fdg45 / aS”

长度限制hm。您无法区分POST处理的含义吗?如果您想要简单的参数(例如排序),我不明白为什么这会成为问题。我想这是您担心的确定性。


您可以使用x-前缀发送任何想要的参数,对标头长度的任何限制将完全是服务器的任意限制。
克里斯·马里西奇

4

我对REST感到不高兴,因为协议不支持OOP,并且Get方法是证明。作为解决方案,您可以将DTO序列化为JSON,然后创建查询字符串。在服务器端,您可以将查询字符串反序列化为DTO。

看一下:

基于消息的方法可以帮助您解决Get方法的限制。您可以像请求正文一样发送任何DTO

Nelibur Web服务框架提供了可以使用的功能

var client = new JsonServiceClient(Settings.Default.ServiceAddress);
var request = new GetClientRequest
    {
        Id = new Guid("2217239b0e-b35b-4d32-95c7-5db43e2bd573")
    };
var response = client.Get<GetClientRequest, ClientResponse>(request);

as you can see, the GetClientRequest was encoded to the following query string

http://localhost/clients/GetWithResponse?type=GetClientRequest&data=%7B%22Id%22:%2217239b0e-b35b-4d32-95c7-5db43e2bd573%22%7D

8
您应该只使用POST。如果url中有一个方法名,则违反了基本的其余设计。这是RPC,请使用POST。
Evert 2014年

3
我认为这没什么大不了的,在使用RESTful网址(即orders / 1)进行开发的过程中,我们会遇到更多问题。对于我来说,Get方法有问题,它与OOP不兼容。谁在乎url的样子:)但是使用基于消息的方法,我们可以创建稳定的远程接口,这确实很重要。PS它不是RPC,而是基于消息的
GSerjo 2014年

3
我认为您错过了REST的全部内容。当您说时,谁在乎url的样子,REST就在乎很多。为何REST与OOP兼容?
shmish111

不,我不仅看得更远
GSerjo 2015年

4

例如,它可与Curl,Apache和PHP一起使用。

PHP文件:

<?php
echo $_SERVER['REQUEST_METHOD'] . PHP_EOL;
echo file_get_contents('php://input') . PHP_EOL;

控制台命令:

$ curl -X GET -H "Content-Type: application/json" -d '{"the": "body"}' 'http://localhost/test/get.php'

输出:

GET
{"the": "body"}

有趣的实验!PHP仅在$_POST通过POST请求和发送正文时读取application/x-www-form-urlencoded。这意味着在GET请求中将忽略主体。在这种情况下:$_GET$_POST在这一点上都非常容易引起误解。更好地利用php://input
Martin Muzatk​​o

3

恕我直言,您只需在中发送JSON编码后的(即encodeURIComponentURL,这样就不会违反HTTP规范并将其JSON送至服务器。


28
是的,但是主要的问题是长度限制,我们如何处理?
塞巴(Sebas)

2

您有一个选项列表,它们比使用带有GET的请求正文要好得多。

假设您有类别和每个类别的项目。两者都由一个id标识(在此示例中为“ catid” /“ itemid”)。您要根据另一个参数“ sortby”以特定的“顺序”进行排序。您要传递“ sortby”和“ order”的参数:

您可以:

  1. 使用查询字符串,例如 example.com/category/{catid}/item/{itemid}?sortby=itemname&order=asc
  2. 对路径使用mod_rewrite(或类似方法): example.com/category/{catid}/item/{itemid}/{sortby}/{order}
  3. 使用随请求传递的单个HTTP标头
  4. 使用其他方法(例如POST)来检索资源。

都有缺点,但是比将GET与身体结合使用要好得多。


0

即使经常使用的工具使用此工具(如本页中经常提到的那样),我仍然认为这是一个非常糟糕的主意,尽管规格未禁止,但过于奇特。

许多中间基础设施可能只是拒绝此类请求。

举例,忘记使用一些现有的CDN在您的网站的前面,像这样的一个

如果查看者GET请求包括正文,CloudFront会向查看者返回HTTP状态代码403(禁止)。

是的,您的客户端库也可能不支持发出此类请求,如本评论所述


0

我在客户端程序中使用Spring框架的RestTemplate,在服务器端,我使用Json主体定义了GET请求。我的主要目的与您的主要目的相同:当请求具有多个参数时,将其放入正文中似乎比将其放入延长的URI字符串中更整齐。是?

但是,可悲的是,它不起作用!服务器端引发了以下异常:

org.springframework.http.converter.HttpMessageNotReadableException:缺少所需的请求正文...

但是我很确定消息代码是由我的客户端代码正确提供的,那么怎么了?

我追踪到RestTemplate.exchange()方法,发现以下内容:

// SimpleClientHttpRequestFactory.class
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory, AsyncClientHttpRequestFactory {
    ...
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        ...
        if (!"POST".equals(httpMethod) && !"PUT".equals(httpMethod) && !"PATCH".equals(httpMethod) && !"DELETE".equals(httpMethod)) {
            connection.setDoOutput(false);
        } else {
            connection.setDoOutput(true);
        }
        ...
    }
}

// SimpleBufferingClientHttpRequest.class
final class SimpleBufferingClientHttpRequest extends AbstractBufferingClientHttpRequest {
    ...
    protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) throws IOException {
        ...
        if (this.connection.getDoOutput() && this.outputStreaming) {
            this.connection.setFixedLengthStreamingMode(bufferedOutput.length);
        }

        this.connection.connect();
        if (this.connection.getDoOutput()) {
            FileCopyUtils.copy(bufferedOutput, this.connection.getOutputStream());
        } else {
            this.connection.getResponseCode();
        }
        ...
    }
}

请注意,在executeInternal()方法中,输入参数'bufferedOutput'包含我的代码提供的消息正文。我通过调试器看到了它。

但是,由于prepareConnection(),executeInternal()中的getDoOutput()始终返回false,这又使bufferedOutput完全被忽略!它不会复制到输出流中。

因此,我的服务器程序未收到消息正文,并引发了该异常。

这是有关Spring框架的RestTemplate的示例。关键是,即使HTTP规范不再禁止消息正文,某些客户端或服务器库或框架仍可能符合旧规范并拒绝GET请求中的消息正文。


您在此处未正确阅读规范或注释。客户端和服务器丢弃请求正文在规范之内。不要使用GET请求主体。
Evert

@Evert我没有正确阅读注释,或者您没有阅读?:)如果向上滚动至Paul Morgan的答案(最热门的答案)并仔细阅读注释,您会发现:“ RFC2616被称为“ HTTP / 1.1 spec”,现在已过时。在2014年,它被替换为RFC 7230-7237。删除了“处理请求时应忽略消息主体”的内容,现在只是“请求消息框架独立于方法语义,即使方法未定义消息主体的任何用途...”

@Evert而且,我使用的是REST测试实用程序“保证”来测试我的Spring-boot后端。放心的和服务器端的Spring-boot都将Json主体保留为GET请求!只有Sping框架的RestTemplate从GET请求中删除主体,所以Spring-boot,rest-assured和RestTemplate是错的吗?

@Evert最后但不是租约,我没有敦促人们在GET请求中使用body,相反,我建议您不要通过分析Sping-framework的RestTemplate的源代码来这样做,所以您为什么反对我的投票?回答?
周六

我没有拒绝你的回答。我只是在澄清任何HTTP实施删除GET请求都是规范。
Evert
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.