当需要一些复杂的参数时,设计HTTP请求的最佳方法是什么?

Kir*_*ohn 31 rest get http uritemplate

我有一些我正在写的Web服务,我想尽可能地保持RESTful.我使用在IIS/ASP.NET/SharePoint中运行的HTTPHandler来托管这些Web服务.

我的大多数服务都期望HTTP GET.我有两个只是返回一些数据(即查询)并将是幂等的,但参数可能有点复杂.它们都可以包括服务参数中的字符,这些字符至少不允许URL的PATH部分.

使用IIS,ASP.NET和SharePoint我发现URL路径中的以下字符甚至没有进入我的HttpHandler,即使Url编码(请求爆炸,我对此没有任何简单的控制) :

  • %(%25)
  • &(%26)
  • *(%2a,但没有Url编码)
  • +(%2b)
  • :(%3a)
  • <(%3c)
  • (%3E)

以下字符使其成为我的HttpHandler,但即使Url编码,UriTemplate也无法正确处理它们:

  • (%23)

  • .(%2e,但没有Url编码; UriTemplate删除了"."如果是/之前的最后一个字符)
  • ?(%3f)的
  • /(%2f - 即使UrlEncoded,UriTemplate也因为显而易见的原因而失败)
  • \(%5c)

所以,我有点彻底,但我需要在查询字符串中测试这些url编码的字符.看起来这在大多数情况下都会起作用.

在我的一个服务中,作为参数的特殊字符在语义上是查询/过滤器的一部分(实际上是搜索服务的搜索项),但在另一个中它们实际上不是查询/过滤器的一部分,所以理想情况下它们是路径而不是查询字符串.

我的问题是,最好的选择是什么?以下是我所知道的一些内容:

  1. 使用HTTP GET和查询字符串. 任何可能使用特殊字符的内容都应该在查询字符串和Url Encoded上. 这是我倾向于的地方,但我担心极长的查询字符串(IE有2083限制)

  2. 在路径中使用HTTP GET和base64编码.对于可能使用特殊字符的任何参数, 请使用Modified Base64 for URL,并将其作为路径的一部分(如果需要). 我试过这个并且它有效,但它有点难看.关于极长查询字符串的问题仍然存在.

  3. 使用HTTP POST和邮件正文. 任何可能使用特殊字符的东西都应该在请求的正文中. 似乎是一个不错的解决方案,但帖子被理解为和(我认为)通常意味着更改(而没有变化发生在这里).

  4. 使用HTTP GET和邮件正文. 任何可能使用特殊字符的东西都应该在请求的正文中.根据SO,这似乎是一个坏主意:请求正文Roy Fielding的HTTP GET.

  5. 根据请求的大小,使用#3和#1或#2的组合.

  6. 其他???

请注意,在某些情况下,我可以更改周围的东西以防止特殊字符(我可能会这样做),但我无法在所有情况下都这样做.


关于URI长度,RFC2616 Sec3.2.1说明如下:

HTTP协议不对URI的长度设置任何先验限制.服务器必须能够处理它们所服务的任何资源的URI,并且如果它们提供可以生成这种URI的基于GET的表单,它应该能够处理无限长度的URI.如果URI长于服务器可以处理的长度,服务器应该返回414(Request-URI Too Long)状态(参见10.4.15节).

  Note: Servers ought to be cautious about depending on URI lengths
  above 255 bytes, because some older client or proxy
  implementations might not properly support these lengths.
Run Code Online (Sandbox Code Playgroud)

此外,Internet Explorer中最大URL长度为2,083个字符.

相关:如何在REST中传递复杂查询?

Nel*_*son 28

没有完美的方法来做到这一点.

正确的HTTP/REST方式是使用GET并将URL中的所有参数作为查询参数.您已经确定了这种方法存在的两个实际问题

  1. 即使URL已编码,您的服务器软件也无法正确传递某些字符.实际上,这让我感到惊讶,你应该更仔细地看看发生了什么,你甚至无法通过URL获得%.您的框架是否为您提供了对PATH_INFO或其他未处理字符的原始访问权限?这可能会给你一个解决方法.
  2. 您的查询字符串可能太长.你在MSIE中提到了2083字节的限制.根据MSIE是否是您的API的客户端,这对您来说可能是也可能不是实际问题.(即:通过Javascript调用JSON API).但根据我的经验,很长的网址最终会在几个地方神秘地破解; 路径上的代理缓存,甚至是状态防火墙.如果您可以完全控制客户端和网络路径,则可能会遇到长URL的危险.如果它是公共API,请忘掉它.

希望您可以在您的环境中进行直接的GET工作.您甚至可能需要考虑重构API以使查询数据更小.

但是如果你不能让GET工作呢?你提出了几种选择.我会马上解雇他们中的两个.不要将内容放在GET请求体中; 如果你尝试过,那么太多的软件会破坏,无论如何它都违反了你想要捕获的REST精神.我不会使用base64编码.它可以帮助您解决问题1,您的服务器没有正确处理URL中的某些字符.但是,如果应用错误,它实际上会使您的URL更长,而不是更短,复杂问题2.即使您正确地使用base64并包含一些压缩,它也不会使URL显着缩短,并且会使客户端变得更加复杂.

您最实用的解决方案可能是选项3,HTTP POST.这不是RESTful; 你应该使用GET进行只读查询.而且,通过缓存GET等,你将失去REST方法的一些优点.另一方面,它可以正常工作,简单地说,可以使用各种各样的Internet基础结构和软件库.然后,您可以通过multipart/form-data encoding,JSON或XML在POST主体中传递所需的数据.(我使用SOAP构建了两个主要的公共Web服务,它只是POST上的XML.它很丑陋而不是RESTful,但它确实可靠地工作.)

REST是一个很棒的设计范例.这是一个指导方针.如果它不适合您的应用程序,请不要觉得您需要坚持使用它.HTTP不擅长使用GET将大量数据传递到服务器.如果您需要巨型查询参数,请执行其他操作.


red*_*ben 13

如果查询太大而无法进入URI,请将查询转换为资源(如已保存的搜索).我为酒店的预订系统开发了一个安静的API; 搜索查询有太多的参数(首选项,房间列表等),所以我把它变成了一个POST到服务器的资源.然后,服务器回复一个唯一标识搜索的URI,哪个正文是已发布的查询+其结果:

POST http://hotels.xyz/searches
body <search><query>...</query></search>
Run Code Online (Sandbox Code Playgroud)

响应

201 Created - Location: http://hotels.xyz/searches/someID
Body <search><query>...</query><results>...</results></search>
Run Code Online (Sandbox Code Playgroud)


Gum*_*mbo 5

我建议您阅读HTTP 1.1规范,尤其是3.2统一资源标识符9.1.1安全方法.希望能回答你的问题.


这是一些额外的信息:

  • 也许大量链接文档之一包含问题的答案,但此回复肯定没有。 (3认同)

len*_*ite 5

如果没有其他功能,请使用带有HTTP GET的自定义HTTP标头.几乎所有客户端都可以设置HTTP标头.

通常,最好在查询字符串中使用URL参数.URL参数太多表示您需要拆分为更细粒度的服务.