5

我正在设计一个(或多或少)在 ASP.NET 和 IIS 上运行的 RESTful 内部 Web 服务。我希望客户端能够在访问大量条目时将查询详细信息传递给服务器,使用 JSON 以已知方式描述查询。问题是发送到服务器的查询会很复杂;它们可能包括聚合、过滤、映射——基本上是LINQ 查询运算符支持的任何内容。这将导致表示查询的 JSON 对象相对较大。

我面临的冲突是,虽然查询GET在 REST 世界中是语义上的,但在GET. 我想出了几个选项来解决这个问题。


选项 1:在请求正文中发送查询对象GET

GET /namespace/collection/ HTTP/1.1
Content-Length: 22

{ /* query object */ }

显然,这是非标准的,并且某些软件可能会在GET具有正文的请求上阻塞。(或者更糟糕的是,简单地剥离正文并在没有它的情况下处理请求,这将导致服务器返回不正确的结果集。)


选项 2:使用非标准 HTTP 动词(可能是QUERY)而不是GET.

QUERY /namespace/collection/ HTTP/1.1
Content-Length: 22

{ /* query object */ }

虽然这并不完全符合 REST 模式,但它(对我而言)似乎是一个安全的替代方案,因为其他软件(例如任何使用 WebDAV 的软件)似乎使用非标准 HTTP 动词并取得了足够的成功。


选项 3:将查询对象放在非标准 HTTP 标头中。

GET /namespace/collection/ HTTP/1.1
ProjectName-Query: { /* query object */ }

此选项将请求保留为GET,但需要在 HTTP 标头中填充可能非常大的对象。我了解某些软件对 HTTP 标头设置了任意长度限制,因此如果对象变得太大,这可能会导致问题。


选项 4:使用POST动词并提供备用端点进行查询。

POST /namespace/collection/query HTTP/1.1
Content-Length: 22

{ /* query object */ }

因为这使用了标准动词而没有标准标题,所以可以保证此方法适用于所有场景。唯一的问题是它偏离了 RESTful 架构,我正在尽我所能保持一致。


这些选项都不是完全正确的。我想知道哪种方式对我正在编写的服务最有意义;它是一个内部 Web 服务(它永远不会向公众公开),但可以通过各种网络安全应用程序(防火墙、内容过滤器等)访问它,我想坚持已知的开发风格、标准和架构尽我所能。

4

8 回答 8

6

I would think about "RESTful querying" as having two resources: Query and QueryResult.

You POST your Query to one end-point (e.g. "POST /queries/") and receive a CREATED Status back with the URI of your specific query (/queries/123) and a nice and RESTful hypertext body telling you the URL of your query result (e.g. /result/123 ). Then you access your query result with a GET /result/123. (Bonus points if you use hypertext to link back to /queries/123 so that the consumer of the query result can check and modify the query.

To elaborate the point I'm trying to make:

If RESTful is basically reduced to "map business entities to URIs" than the obvious question arises: "how can I query a subset of my entities"? Often the solution is "adding a query string to the 'all entities of this type'-URL" - Why else would it be called "query string"?. But it starts to feel "wrong" - as stated in the OP - if you want to have a full fledged query interface.

The reason is that with this requirement the Query becomes a full business object itself and is no longer an addendum to an resource address. It's no longer secondary but primary. It becomes important enough to become a resource in its own right - with it's own address (e.g. URL) and representation.

于 2013-09-21T08:18:03.643 回答
3

我会使用选项 4。很难将大型搜索请求的 json 中的查询表示放入 url,尤其是针对搜索服务器。我同意,在这种情况下,它不适合 Restful 风格,因为 URI 无法识别资源。REST 是一个指南。如果 REST 无法实现该场景,那么我想做一些解决问题的事情。在这里使用 POST 并不平静,但它似乎是正确的解决方案。

于 2013-09-18T22:28:31.173 回答
2

我不确定它对你来说有多“规范”,但你可以认真看看OData(开放数据协议):

OData 是用于创建和使用数据 API 的标准化协议。OData 建立在 HTTP 等核心协议和 REST 等普遍接受的方法之上。结果是一种公开全功能数据 API 的统一方式。

即使您不按原样实现它,也有可以重用的想法。

具体来说,OData 定义了批处理。它用于执行在单个 HTTP 请求中发送的多个操作。因此,使用 OData,您有两种选择:

  1. 对不太长的查询使用 GET + 查询字符串操作
  2. 对更大的事情使用 POST + 多部分正文操作。

有关 OData 上下文中最大 uri 长度的更多信息:OData Url Length Limitations

此外,许多安全设备(路由器、防火墙等)根本不会让您的选项 1、2 和 3 通过。GET + Body 是不寻常的,GET + 一个大的表单值可能会被杀死,自定义 HTTP 动词也很不寻常。

总的来说,我认为 POST + body 似乎是最好的选择(它是否是严格的多部分 - 就像在 OData 中一样 - 取决于你)

于 2013-09-23T07:29:47.227 回答
1

最好的方法是序列化搜索 JSON 对象并将其作为查询参数传递。你确定它对于现代浏览器和服务器来说太长了吗?现代浏览器和服务器可以处理相当大的 GET 查询参数长度,数千个字符。

可能是一个扩展标题,例如X-Custom-Query-Parameters-JSON对象是否将更多地达到 8k 个字符的顺序。

在您的特定情况下,序列化的 JSON 对象有多少个字符?

关于字符限制的一些相关问题

QueryString / GET / URL 参数的限制是什么

是否有实用的 HTTP 标头长度限制?

于 2013-09-25T03:04:54.757 回答
1

在考虑了更多之后,我将给出另一个答案。

当您声明 JSON 表示将“相对较大”时,您是什么意思,在估计的字符数中?IE 可以处理超过 2,000 个字符的 URL。查询会变得比这更大吗?因为我认为查询字符串是要走的路。现在我正在开发一个使用 JSONP 的系统,所以我们别无选择,只能在查询字符串中将所有数据作为 JSON 包传递,它工作正常。使用 GET 动词不仅在语义上是正确的,而且还包括能够将 URL 添加到结果中的功能。用户可以通过电子邮件或您在内部使用的其他电子通信系统轻松共享指向数据结果的链接。

于 2013-09-19T14:13:36.187 回答
1

我不确定这是否有帮助,但即使对于所有 Quickbooks API、返回大型结果集(如 Read All)的查询或返回大型 JSON 结果集的 LINQ 扩展器查询,我们也将 GET 与相关内容类型和编码(如 ASCII)一起使用。请求将compressionFormat 用作None,响应使用GZIP compressionFormat。 https://developer.intuit.com/apiexplorer?apiName=V3QBO

于 2013-09-24T08:39:21.210 回答
0

一个有趣的问题。我没有关于你想要做什么的细节,但我想知道优雅地处理一个资源是否太多。您可能希望根据请求的主要特征将其分解为几种不同的类型。如果您只是想通过 HTTP 请求公开应该是 SQL 查询的内容,那么我认为没有任何方法可以在没有混乱的情况下实现它。只需在查询字符串中传递 SQL 查询,然后停止尝试找到正确的方法 - 它不存在。

于 2013-09-18T20:37:42.543 回答
0

使用 POST,并将查询/参数作为键值对在正文中作为 json 传递。在您的 asp.net 代码中将有效负载转换为字典对象也变得更加容易。

Dictionary<string,object>
于 2013-09-23T21:59:30.650 回答