Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
同一资源的不同RESTful表示_Rest_Http_Url_Web Applications_Restapi - Fatal编程技术网

同一资源的不同RESTful表示

同一资源的不同RESTful表示,rest,http,url,web-applications,restapi,Rest,Http,Url,Web Applications,Restapi,我的应用程序的资源位于/foo。通常,它由HTTP响应负载表示,如下所示: {"a": "some text", "b": "some text", "c": "some text", "d": "some text"} 客户端并不总是需要此对象的所有四个成员。客户机用什么RESTfully语义方法告诉服务器它在表示中需要什么?e、 g.如果需要: {"a": "some text", "b": "some text", "d": "some text"} 它应该如何获取它?一些可能性(如果

我的应用程序的资源位于
/foo
。通常,它由HTTP响应负载表示,如下所示:

{"a": "some text", "b": "some text", "c": "some text", "d": "some text"}
客户端并不总是需要此对象的所有四个成员。客户机用什么RESTfully语义方法告诉服务器它在表示中需要什么?e、 g.如果需要:

{"a": "some text", "b": "some text", "d": "some text"}
它应该如何
获取它?一些可能性(如果我误解了REST,我正在寻找更正):

  • GET/foo?sections=a、b、d
    • 查询字符串(毕竟称为查询字符串)的意思似乎是“查找与此条件匹配的资源并告诉我它们的情况”,而不是“根据此定制向我表示此资源”
  • GET/foo/a+b+d
    我最喜欢的如果REST语义没有涵盖这个问题,因为它很简单。
    • 破坏URI不透明度,违反HATEOAS
    • 似乎打破了资源(URI的唯一含义是标识一个资源)和表示之间的区别。但这是有争议的,因为它与表示可呈现的
      /widget/
      资源列表的
      /widget/
      一致,我从来没有遇到过问题
  • 放松我的限制,响应
    GET/foo/a
    等,让客户机根据它想要的
    /foo
    组件发出请求。
    • 增加开销,如果
      /foo
      有数百个组件,而客户端需要其中的100个,这可能会成为一场噩梦
    • 如果我想支持
      /foo
      的HTML表示,我必须使用Ajax,如果我只想要一个可以被爬网、由极简浏览器呈现的HTML页面,这是有问题的
    • 为了维护HATEOAS,它还要求指向这些“子资源”的链接存在于其他表示中,可能位于
      /foo
      {“a”:{“url”:/foo/a”,“content”:“some text”},…}
  • 请求正文中的
    GET/foo
    内容类型:application/json
    {“sections”:[“a”、“b”、“d”]}
    • 不可标记和不可缓存
    • HTTP没有为
      GET
      定义正文语义。这是合法的HTTP,但我如何保证某些用户的代理不会从
      GET
      请求中删除主体
    • 我不允许我在
      GET
      请求中添加主体,因此我不能将其用于测试
  • 自定义HTTP头:
    需要的部分:A、b、d
    • 如果可能的话,我宁愿避免使用自定义标题
    • 不可标记和不可缓存
  • POST/foo/requests
    内容类型:application/json
    {“sections”:[“a”、“b”、“d”]}
    ,在请求正文中。接收带有
    位置:/foo/requests/1的
    201
    。然后
    GET/foo/requests/1
    接收所需的
    /foo
    • 笨重的;需要来回和一些奇怪的代码
    • 取消标记和取消缓存,因为
      /foo/requests/1
      只是一个别名,只能使用一次,并且只能保留到被请求为止

如果a、b、c是像admin for role属性这样的资源的属性,那么正确的方法是使用您建议的第一种方法
GET/foo?sections=a、b、d
,因为在这种情况下,您将对
foo
集合应用过滤器。否则,如果a、b和c是
foo
集合的单个资源,则接下来的方法是执行一系列
GET
请求
/foo/a/foo/b/foo/c
。正如您所说,这种方法的请求有效负载很高,但它是遵循Restfull方法的正确方法。我不会使用第二个提议​​因为url中的加号字符有特殊的含义


另一个建议是放弃使用GET和POST,为
foo
集合创建一个动作,例如:
/foo/filter
/foo/selection
或表示集合上动作的任何动词。通过这种方式,拥有一个post请求主体,您可以传递一个json资源列表。

我建议使用querystring解决方案(您的第一个)。你反对其他选择的论点是很好的论点(我在实践中遇到过这些论点,试图解决同样的问题)。特别是,“放松约束/响应
foo/a
”解决方案可以在有限的情况下工作,但在实现和使用方面给API带来了很多复杂性,根据我的经验,不值得为此付出努力

我将用一个常见的例子来弱化你的“似乎意味着”的论点:考虑一个大对象列表的资源(<代码>获取/客户< /代码>)。对这些对象进行分页是完全合理的,使用querystring进行分页是很常见的:

GET/Customers?offset=100&take=50
。在这种情况下,querystring不会对列出的对象的任何属性进行过滤,而是为该对象的子视图提供参数

更具体地说,我要说的是,您可以通过以下使用查询字符串的标准来保持一致性和HATEOAS:

  • 返回的对象应与从Url返回的对象(不带querystring)相同
  • 没有querystring的Uri应该返回完整的对象-具有相同Uri的querystring的任何视图的超集。因此,如果缓存未修饰Uri的结果,就知道拥有完整的实体
  • 为给定querystring返回的结果应该是确定性的,因此具有querystring的uri很容易缓存
但是,这些URI的回报有时会带来更复杂的问题:

  • 为仅因查询字符串不同的URI返回不同的实体类型可能是不可取的(
    /foo
    是一个实体,但{ "id": 5, "name": "John", "surename": "Doe", "marital_status": "single", "sex": "male", ... }
/customers/5?fields=name,surename
{
   "name": "John",
   "surename": "Doe"
}