针对超长URI的REST最佳实践

时间:2010-01-15 10:50:46

标签: http url rest uri

我有REST服务,应该通过GET接收非常长的查询。比方说,我想用许多地理坐标来查询服务,以找出有关所有这些坐标的信息。

1)我的第一个想法是使用servlet容器的长URI和increase the max URI length

看起来像这样:

GET http://some.test/myresource?query={really big JSON object}

但是由于旧的代理服务器,似乎长度超过2 KB的URI不可靠(是吗?)。

2)我的解决方法是首先通过POST创建临时资源,并使用此资源的URI作为实际GET请求中的参数。这看起来像这样:

POST http://some.test/temp
Request Body: {really big JSON object}

201 Created Location: http://some.test/temp/12309871

GET http://some.test/myresource?query=http://some.test/temp/12309871

3)使用GET请求的正文。我已经阅读了问题的答案,是否使用GET请求的主体进行查询是一个好主意,并且共识是:不。甚至罗伊菲尔丁说这是bad idea

4)另一种方法可能是将POST解释为“创建查询结果资源”并在请求后删除此资源。但我认为这不是RESTful而是一个坏主意。

使用GET请求处理大型查询是否有更好的方法?

6 个答案:

答案 0 :(得分:3)

我认为REST中的重点是处理“文档”(或类似的东西)。请求的URI部分用于标识唯一要处理的资源。相反,正文部分是文档的“内容”部分。

因此,请使用请求的“正文”部分。

另请注意,“GET”请求的语义不应该用于“PUTTING”或“POSTING”文档(与上面的“查询”示例相关的评论似乎是“创建”一个对象)

无论如何,正如您所指出的,URI部分是有限的(我确信这是有充分理由的。)


如果您关注缓存,那么使用ETag / Last-Modified字段(与“条件GET”一起使用有助于实现此目的。

答案 1 :(得分:3)

如果您使用GET请求发送大型对象,则表明您没有正确使用REST。

  • GET应该用于检索 资源(通过某种独特的 标识符)
  • 应该使用POST 创建资源(包含内容 在体内)
  • PUT应该用于 更新资源(使用 身体内容)
  • DELETE应该用于删除资源

如果您遵循这些准则,则永远不会有过长的URI。

这里有一些最佳做法REST指南:http://www.xml.com/pub/a/2004/08/11/rest.html

答案 2 :(得分:3)

使用PUT

为什么呢?原因如下:

  • 仅仅因为动词PUT'可以更新资源,并不意味着它会或者必须改变资源的基本状态。
  • PUT的API端不应创建新的资源标识符(url)。是的,从技术上讲,PUT可以使用客户端指定的标识符,但在这种情况下,您将访问现有资源。
  • PUT就像GET一样,它应该是幂等的,这意味着请求的结果总是相同的,无论你多久调用它,它都没有副作用。< / LI>

PUT表示您将资源数据放入现有资源。就文档/博客文章世界中的文章或帖子而言,就像将某个文档的新版本上载到现有资源URL一样。如果您将相同的修订上载到同一个URL,则您获取的资源中不应更改任何内容。

在您的情况下,地理位置数据是您上传的一些新资源数据,每次发出相同请求时,您获得的结果应该相同。

对请求使用GET动词的更纯粹的方法可能是:

  • 为查询资源类型
  • 创建端点
  • 将JSON查询详细信息集发布到查询资源端点并获取查询资源的标识符(假设它返回123的查询ID)
  • 向get请求提交查询标识http://some.test/myresource?query_id=123
  • 删除查询资源123

我认为纯方法比在主体中使用PUT和查询资源数据要花费更多的开销。

答案 3 :(得分:2)

您的第二个选项略有不同。创建一个名为QueryMaker的处理器资源。将参数发布到它并让它重定向到一个临时查询资源,该资源将返回结果。

POST /QueryMaker
Body: Big Json representation of parameters

303: See Other
Location: http://example.org/TemporaryQueries/123213

答案 4 :(得分:0)

开放Web上URL长度的最大限制实际上是IE,constraints them to 2083 characters

某些代理(例如,除了最新版本的Squid之外的所有代理)都会将它们限制为大约4k,尽管这是moving towards 8k slowly

根据您的使用情况,您的#2解决方法是一种很好的方法。

某些实现可能允许在GET上发送正文,而其他人不允许这样做,因此对于互操作性和理论原因来说,这是一个坏主意。最重要的是,缓存如何知道将什么用作密钥?

答案 5 :(得分:-1)

你不能只用GET请求体发送大的JSON数据,而不是创建临时资源吗?

虽然它不是100%kosher,但我发现它与firefox以及IE和IMO很好地协同工作,查询字符串不够优雅,并且通常会暴露不属于URI的实现细节。如果您需要最新数据,请确保添加cache buster querystring参数,因为服务器在确定是否可以返回缓存响应时会忽略数据。

有关GET请求正文中填充数据的优缺点的讨论,请参阅here