带请求正文的HTTP GET

Eve*_*ert 1896 rest http http-get

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

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

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

我的问题:

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

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

Pau*_*gan 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认同)
  • 我不同意“这样做永远没有用”。当我想要“获取”资源时,我经常需要提供参数,而不仅仅是 Id,因此我总是创建一个特定于我的需求的请求 JSON 对象,并且我总是最终使用“Post”而不是“Get” ` 因为这个。所以我做了一个“Post”请求来“Get”资源(我知道我知道) (8认同)
  • @LuisArmando 新的 RFC 意味着,如果您将带有有效负载正文的 HTTP GET 发送到旧应用程序,如果它遵循旧的 RFC 规范,则可以拒绝您的请求。但是,如果您正在创建一个新应用程序并且遵循 RFC 7231,则 GET 方法可以接受有效负载主体,这很好。 (6认同)
  • @GordonM唉,显然他们没有.这个答案是正确的,它违反了GET请求的语义,以根据请求体中的任何数据返回响应. (4认同)
  • 假设您想在一次调用中获取实体列表。(1,4,21, ..., 100027001)。URL 和查询字符串的最大长度是 2083 个字符。您可以在服务器上增加它,但客户端可能会强制执行它。那么你应该如何执行你的查询呢?很简单,您使用主体中的 Id 列表调用 GET:GetByIds(List<int> ids)。另外,如果您的 URL 参数由于任何其他原因有一个过大的查询字符串怎么办?您应该将查询字符串放在 GET 调用的主体中。如果您查看 Odata 规范,如果没有带有主体的 GET,就无法完全实现。 (4认同)
  • PostMan最近还开始允许GET在体内进行测试。 (4认同)
  • @AdityaPatil 我认为结论是你可以做到,即使你不一定应该这样做。最坏的情况下,您可以使用帖子来代替。 (4认同)
  • “不,这样做是没有用的。”这是错误的。就像,真的错了。并非所有 get 请求参数都可以容纳 url 的最大大小。在这些情况下,你需要一个身体。在某些情况下,get 请求可以传递任意长度的参数。看到这个作为最佳答案真的很令人沮丧 (4认同)
  • Fastcatch是正确的,@ Artem Nakonechny即使您在技术上是正确的,也可以阅读[RFC7231](https://tools.ietf.org/html/rfc7231#section-4.3.1)并说:**发送有效载荷主体GET请求上的内容可能会导致某些现有实现拒绝该请求** (3认同)
  • 我正在阅读这些答案是因为 Elastic Search 查询。我想我不是唯一一个@GordonM (3认同)
  • 我认为另一种选择是,您应该更喜欢将 GET 与 uri/query 参数一起使用进行检索,并且仅当/如果您遇到这样做的限制时,才将 GET 与请求正文一起使用。我很少需要这样做。但即使在这种情况下,我还是建议使用带有请求正文的 GET 来检索比 POST 更好。至少 GET 准确地识别了请求的目的。 (3认同)
  • 这是一个规范告诉您不要做某事但没有提供现实替代方案的示例。可能存在需要请求复杂有效负载(例如要返回的属性列表)的用例,而这些负载很难适应 URL。唯一的办法是将此类数据放入请求正文中。 (3认同)
  • Aetherus,这可以工作,但现在您的主体有效负载中有路由详细信息。这是客户必须理解的协议。恕我直言,您使界面变得复杂却没有任何好处。 (2认同)
  • @Sam 来自 HTTP/1.1 规范:*如果请求方法不包含为实体主体定义的语义,则在处理请求时应该忽略消息主体*。`GET` 方法没有为请求体指定语义,所以服务器应该忽略它们。 (2认同)
  • 那么有什么推荐呢?通过 get 请求传递主体是否符合最佳实践? (2认同)
  • “即使它与从服务器获取数据有关?” - GET 的语义目的不是任意只读操作。它获取由 URI 标识的资源的表示形式。如果您需要一个读取操作的正文,它就不符合 GET 请求语义,因为您不再只是获取 URI 的表示形式。不过,您可能会喜欢即将推出的“SEARCH”方法。 (2认同)

cas*_*key 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认同)
  • 然后,人们可能会争辩说 .NET Framework 实现是不正确的。 (3认同)
  • @AbhijeetPatel AJAX 请求不会随 GET 请求一起发送正文数据,因为 [W3C XMLHttpRequest 规范](http://www.w3.org/TR/XMLHttpRequest/#the-send()-method) 不会允许它(这与 HTTP 规范没有明显矛盾)。 (2认同)
  • @ user437899如果您尝试发送带有GET请求的正文,.NET Framework将抛出异常. (2认同)

Dar*_*ler 140

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

  • 使用ETag/Last-Modified标头字段以这种方式提供帮助:当使用"条件GET"时,代理/缓存可以对此信息起作用. (9认同)
  • 您可以通过查询参数中的主体校验和来修复该问题 (5认同)
  • @jldupont缓存使用验证器的存在来了解是否可以重新验证过时响应,但是,它们不会用作主缓存密钥或辅助缓存密钥的一部分. (2认同)
  • 对于缓存,只需将 body 的哈希值添加到 url 即可!:) (2认同)

Mar*_*son 94

GET,有身体!?

\n

就规范而言,您可以,但是,正如我们将看到的,不明智地这样做并不是一个好主意。

\n

RFC 7231 \xc2\xa74.3.1规定主体“没有定义的语义”,但这并不是说它是被禁止的。如果您将正文附加到请求中,那么您的服务器/应用程序将如何处理它,这取决于您。RFC 继续指出 GET 可以是“各种数据库记录的编程视图”。显然,这样的视图多次是由大量输入参数定制的,将这些输入参数放入请求目标的查询组件中并不总是方便甚至安全。

\n

好处:我喜欢这些措辞。很明显,读取/获取资源不会对服务器产生任何可观察到的副作用(该方法是“安全的”),并且无论第一个请求的结果如何,都可以重复请求以达到相同的预期效果(该方法是“幂等的”)。

\n

坏处: HTTP/1.1 的早期草案禁止 GET 有正文,并且据称,某些实现甚至直到今天都会删除正文、忽略正文或拒绝消息。例如,哑 HTTP 缓存可能仅根据请求目标构造缓存密钥,而忽略主体的存在或内容。甚至更愚蠢的服务器可能会如此无知,以至于将正文视为新请求,这实际上被称为“请求走私”(这是“向一个设备发送请求,而另一设备不知道的行为” -来源)。

\n

由于我认为主要是对实现之间的不可操作性的担忧,正在进行的工作建议将 GET 主体分类为“不应该”,“除非[请求]直接发送到先前已指示的原始服务器,在或在带外,这样的请求是有目的的并且将得到充分的支持”(强调我的)。

\n

解决办法:有一些技巧可以用来解决这种方法的一些问题。例如,只需将从正文派生的哈希值附加到查询组件,或者通过响应cache-control: no-cache来自服务器的标头来完全禁用缓存,即可将正文不感知的缓存间接变为正文感知。

\n

遗憾的是,当涉及到请求链时,人们通常无法控制甚至不知道所有当前和未来的 HTTP 中介以及它们将如何处理 GET 主体。这就是为什么这种方法通常被认为是不可靠的。

\n

但是POST,不是幂等的!

\n

POST是一个替代方案。POST 请求通常包含消息正文(仅供记录,正文不是必需的,请参阅RFC 7230 \xc2\xa73.3.2)。RFC 7231 ( \xc2\xa74.3.3 )中的第一个用例示例是“向数据处理过程提供数据块[.​​..]”。因此,就像对 body 进行 GET 一样,后端的 body 会发生什么取决于您。

\n

好处:当人们希望出于任何目的发送请求正文时,也许可以采用一种更常见的方法,因此,团队成员可能会产生最少的噪音(有些人可能仍然错误地认为 POST 必须创建资源)。

\n

此外,我们经常传递参数的是一个对不断变化的数据进行操作的搜索函数,并且只有在响应中提供了明确的新鲜度信息时,POST 响应才可缓存。

\n

缺点: POST 请求未定义为幂等,导致请求重试犹豫。例如,在页面重新加载时,浏览器不愿意重新提交 HTML 表单而不用不可读的神秘消息提示用户。

\n

修复:好吧,仅仅因为 POST 没有被定义为幂等并不意味着它一定不能是幂等的。事实上,RFC 7230 \xc2\xa76.3.1写道:“知道(通过设计或配置)对给定资源的 POST 请求是安全的用户代理可以自动重复该请求”。因此,除非您的客户端是 HTML 表单,否则这可能不是一个真正的问题。

\n

QUERY是圣杯

\n

有一个新方法的提案QUERY,它定义了消息正文的语义并将该方法定义为幂等的。看到这个

\n

编辑:作为旁注,在发现他们仅使用PUT服务器端搜索功能的请求的代码库后,我偶然发现了这个 StackOverflow 问题。他们的想法是包含一个带有参数的主体并且也是幂等的。PUT 的问题是请求正文具有非常精确的语义。具体来说,PUT“请求创建目标资源的状态或用[主体中]的状态替换”(RFC 7231 \xc2\xa74.3.4)。显然,这排除了 PUT 作为可行的选择。

\n

  • “数百年前编写的遗留软件可能会丢弃主体或以其他方式忽略它”——据我所知,这包括**当前的每个浏览器**。 (3认同)

Dav*_*bin 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认同)

jle*_*our 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认同)

Ser*_*Seb 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认同)

fij*_*ron 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
Run Code Online (Sandbox Code Playgroud)

(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.
Run Code Online (Sandbox Code Playgroud)

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

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

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

izr*_*rik 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])
Run Code Online (Sandbox Code Playgroud)

发起请求.可选参数提供请求正文.如果请求方法是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认同)

ger*_*tas 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>.


Xen*_*ite 7

您有一个选项列表,这些选项比使用带有 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)来检索资源。

都有它们的缺点,但比使用带有 body 的 GET 好得多。


GSe*_*rjo 6

我很不高兴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
Run Code Online (Sandbox Code Playgroud)

  • 你应该只使用POST.如果网址中有方法名称,则表示您违反了基本的休息设计.这是RPC,使用POST. (8认同)
  • 我认为你错过了REST的全部内容.当你说,谁在乎网址是什么样的时候,很好地关注REST.为什么REST与OOP兼容? (4认同)
  • 我不认为这是一个大问题,我们在RESTful url(即orders/1)的开发过程中遇到了更多问题.至于我,Get方法有问题,它与OOP不兼容.谁关心网址是什么样的:)但是基于消息的方法我们可以创建稳定的远程接口,这非常重要.PS它不是RPC,它是基于消息的 (3认同)

clo*_*ead 5

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


cha*_*haz 5

不符合 base64 编码的标头呢?“一些应用程序参数:sdfSD45fdg45/aS”

长度限制嗯。你不能让你的 POST 处理区分含义吗?如果你想要像排序这样的简单参数,我不明白为什么这会成为一个问题。我想你肯定担心。


Fré*_*ric 5

即使一个流行的工具使用了这个,正如本页经常引用的那样,我认为这仍然是一个很糟糕的主意,因为它太奇特了,尽管规范没有禁止。

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

举例来说,忘记在您的网站前面使用一些可用的 CDN,如下所示

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

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


Chr*_*ard 5

如果您想允许带有正文的 GET 请求,一种方法是支持带有标头“X-HTTP-Method-Override: GET”的 POST 请求。此处描述: https: //en.wikipedia.org/wiki/List_of_HTTP_header_fields。此标头意味着虽然方法是 POST,但应将请求视为 GET。正文允许用于 POST,因此您确信没有人会丢弃您的 GET 请求的有效负载。

此标头通常用于通过某些无法识别这些方法的代理发出 PATCH 或 HEAD 请求,并用 GET 替换它们(调试起来总是很有趣!)。