OData Version 4.01
1 简介
开放数据协议(OData)使得能够创建基于REST的数据服务,允许使用统一资源定位符(URL)标识和在数据模型中定义的资源通过简单的HTTP消息被Web客户端发布和编辑。本规范定义了协议的核心语义和行为方面。
[OData-URL] 规范定义了一组用于构建URL的规则,以标识由OData服务公开的数据和元数据,同时还定义了一组保留的URL查询选项。
[OData-CSDLJSON] 规范定义了由 OData 服务公开的实体数据模型的 JSON 表示形式。
[OData-CSDLXML] 规范定义了由OData服务公开的实体数据模型的XML表示形式。
[OData-JSON] 文档规定了使用OData交换的资源表示的JSON格式。
1.0 知识产权政策
此规范是根据 OASIS IPR政 策的 RF on RAND Terms 模式提供的,这是技术委员会成立时选择的模式。有关是否已披露可能对实施此规范至关重要的任何专利以及任何专利许可条款的提供,请参阅 TC 网页的知识产权部分(https://www.oasis-open.org/committees/odata/ipr.php)。
1.1 术语
本文档中的关键词 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, 和 “OPTIONAL” 应按照 [RFC2119] 中所描述的方式进行解释。
1.2 规范性引用文件
[ OData-ABNF ] OData ABNF 构造规则版本 4.01。
请参阅封面页“其他工件”部分中的链接。
[ [OData-Aggregation]] 数据聚合的 OData 扩展版本 4.0。
请参阅封面页“相关工作”部分中的链接。
OData-CSDL JSON] OData 通用架构定义语言 (CSDL) JSON 表示形式版本 4.01。请参阅封面页“相关工作”部分中的链接。
[ OData-CSDLXML] OData 通用架构定义语言 (CSDL) XML 表示版本 4.01。 请参阅封面页“相关工作”部分中的链接
[ OData-JSON ] OData JSON 格式版本 4.01。
请参阅封面页“相关工作”部分中的链接。
[ OData-URL ] OData 版本 4.01 第 2 部分:URL 约定。
请参阅封面页“其他工件”部分中的链接。
[ OData-VocCap ] OData 词汇表 4.0 版:功能词汇表。
请参阅封面页“相关工作”部分中的链接。
[ OData-VocCore ] OData 词汇表版本 4.0:核心词汇表。
请参阅封面页“相关工作”部分中的链接。
[ RFC2046 ] Freed, N. 和 N. Borenstein,“多用途 Internet 邮件扩展 (MIME) 第二部分:媒体类型”,RFC 2046,1996 年 11 月。https: //tools.ietf.org/html/rfc2046 。
[ RFC2119 ] Bradner, S.,“RFC 中用于指示需求级别的关键字”,BCP 14,RFC 2119,1997 年 3 月。https: //tools.ietf.org/html/rfc2119。
[ RFC3987 ] Duerst, M. 和 M. Suignard,“国际化资源标识符 (IRI)”,RFC 3987,2005 年 1 月。https: //tools.ietf.org/html/rfc3987。
[ RFC5646 ] Phillips, A., Ed. 和 M. Davis, Ed.,“用于识别语言的标签”,BCP 47,RFC 5646,2009 年 9 月。http: //tools.ietf.org/html/rfc5646。
[ RFC5789 ] Dusseault, L.和 J. Snell,“HTTP 修补方法”,RFC 5789,2010 年 3 月。http: //tools.ietf.org/html/rfc5789。
[ RFC7230 ] 菲尔丁,R.,编辑。和 J. Reschke,Ed.,“超文本传输协议 (HTTP/1.1):消息语法和路由”,RFC 7230,2014 年 6 月。https: //tools.ietf.org/html/rfc7230。
[ RFC7231 ] 菲尔丁,R.,编辑。和 J. Reschke,Ed.,“超文本传输协议 (HTTP/1.1):语义和内容” ,RFC 7231,2014 年 6 月。https: //tools.ietf.org/html/rfc7231。
[ RFC7232 ] 菲尔丁,R.,编辑。和 J. Reschke,Ed.,“超文本传输协议 (HTTP/1.1):条件请求” ,RFC 7232,2014 年 6 月。https: //tools.ietf.org/html/rfc7232 。
[RFC7240] Snell, J.,“HTTP 首选标头”, RFC 7240,2014 年 6 月。https://tools.ietf.org/html/rfc7240。
[[RFC7617] Reschke, J.,“‘基本’HTTP 身份验证方案”,RFC 7617,2015 年 9 月。https : //tools.ietf.org/html/rfc7617。
1.3 排版约定
本规范定义的关键字使用这种等宽字体。
规范的源代码使用这种段落样式。
本规范的某些部分用非规范性示例进行说明。
示例 1:描述示例的文本使用此段落样式
非规范示例使用此段落样式。
本文档中的所有示例都是非规范性的,仅供参考。
除非另有说明,所有其他文本均为规范性文本。
2 概述
OData 协议是一种通过 RESTful 接口与数据进行交互的应用层协议。该协议支持对数据模型的描述以及根据这些模型进行数据的编辑和查询。它提供以下功能:
- 元数据:特定服务公开的数据模型的机器可读描述。
- 数据:数据实体的集合以及它们之间的关系。
- 查询:请求服务对其数据执行一组过滤和其他转换,然后返回结果。
- 编辑:创建、更新和删除数据。
- 操作:调用自定义逻辑
- 词汇表:附加自定义语义
OData 协议与其他基于 REST 的 Web 服务方法的不同之处在于,它提供了一种统一的方式来描述数据和数据模型。这提高了系统之间的语义互操作性,并允许生态系统的出现。
为此,OData 协议遵循以下设计原则:
- 更喜欢适用于各种数据源的机制。特别是,不要假设关系数据模型。
- 可扩展性很重要。服务应该能够支持扩展功能,而不会让客户端不知道这些扩展。
- 遵循 REST 原则。
- OData 应逐步构建。一个非常基本的、合规的服务应该很容易构建,只需要额外的工作来支持额外的功能。
- 保持简单。解决常见情况并在必要时提供可扩展性。
3 数据模型
本节提供实体数据模型 (EDM) 的高级描述:用于描述 OData 服务公开的数据的抽象数据模型。OData 元数据文档是为客户端使用而公开的服务数据模型的表示。
EDM 中的中心概念是实体、关系、实体集、操作和功能。
实体是实体类型的实例(例如 Customer、Employee 等)。
实体类型被命名为带有键的结构化类型。它们定义实体的命名属性和关系。实体类型可以通过从其他实体类型的单一继承来派生。
实体类型的键由实体类型的原始属性(例如 CustomerId、OrderId、LineId 等)的子集组成。
复杂类型是由一组属性组成的无键命名结构化类型。这些是值类型,其实例不能在其包含实体之外被引用。复杂类型通常用作实体中的属性值或操作的参数。
作为结构化类型定义的一部分声明的属性称为声明属性。结构化类型的实例可能包含其他未声明的动态属性。动态属性不能与声明的属性同名。允许客户端保留其他未声明属性的实体或复杂类型称为开放类型。
从一个实体到另一实体的关系表示为导航属性。 导航属性通常定义为实体类型的一部分,但也可以作为未声明的动态导航属性出现在实体实例上。每个关系都有一个基数。
枚举类型被称为基元类型,其值被命名为具有基础整数值的常量。
类型定义被命名为具有固定方面值(例如最大长度或精度)的原始类型。类型定义可以用来代替原始类型属性,例如在属性定义中。
实体集是实体的命名集合(例如,Customers 是包含 Customer 实体的实体集)。实体的键唯一标识实体集中的实体。如果多个实体集使用相同的实体类型,则相同的键值组合可以出现在多个实体集中,并标识不同的实体,其中出现此键组合的每个实体集一个。每个实体都有不同的实体 ID。实体集提供数据模型的入口点。
操作允许在数据模型的某些部分上执行自定义逻辑。函数 是没有副作用的操作,并且可以支持进一步的组合,例如,具有附加的过滤器操作、函数或动作。操作 是允许副作用(例如数据修改)的操作,并且不能进一步组合以避免非确定性行为。操作和函数要么绑定到某个类型,使它们能够作为该类型实例的成员进行调用,要么未绑定,在这种情况下它们被称为静态操作。操作导入 和函数导入允许从服务根调用未绑定的操作和函数。
单例是命名实体,可以作为实体容器的直接子级进行访问。单例也可以是实体集的成员。
OData 资源是模型中可寻址的任何内容(实体集、实体、属性或操作)。
有关 OData 实体数据模型的详细信息,请参阅 [OData-CSDLJSON] 或 [OData-CSDLXML] 。
3.1 注释
模型和实例元素可以用 Annotations 进行装饰。
注释可用于指定有关元素的单个事实(例如它是否为只读),或定义一个常见概念(例如人或电影)。
应用注解由一个术语(应用的注解的命名空间限定名称)、一个目标(术语应用的模型或实例元素)和一个值组成。该值可以是静态值,也可以是一个表达式,该表达式可能包含一个注解实体的一个或多个属性的路径。
注释术语在元数据中定义,并具有名称和类型。
公共命名空间中的一组相关术语包含词汇表。
4 服务模型
OData 服务是使用通用数据模型定义的。该服务以机器可读的形式公布其具体数据模型,允许通用客户端以明确定义的方式与服务交互。
OData 服务公开两个定义良好的资源来描述其数据模型:服务文档和元数据文档。
服务文档 列出了可以检索的实体集、函数和单例。客户可以使用服务文档以超媒体驱动的方式导航模型。
元数据文档描述 OData 服务理解的类型、集合、功能和操作。客户端可以使用元数据文档来了解如何查询服务中的实体并与之交互。
除了这两种“固定”资源之外,OData 服务还包含动态资源。其中许多资源的 URL 可以根据元数据文档中的信息计算出来。
4.1 实体 ID 和实体引用
实体集中的实体由其键值唯一标识,而实体也由持久的、不透明的、全局唯一的实体 ID 唯一标识。实体 ID 必须是 [RFC3987] 中定义的 IRI ,并且可以在有效负载、标头和 URL 中表达为适当的相对引用。虽然客户端必须准备好接受任何 IRI,但服务必须在此版本的规范中使用有效的 URI,因为当前 EntityId 标头中没有 IRI 的无损表示。
强烈建议服务使用OData-URL中定义的实体的规范 URL作为其实体 ID,但客户端不能假设实体 ID 可用于定位实体,除非将 Core.DereferenceableIDs 术语应用于实体容器,客户端也不能从实体 ID 的结构中假设任何语义。规范资源$entity提供了将实体 ID 解析为实体表示的 通用机制。
使用实体 ID 标准 URL 约定的服务使用术语 Core.ConventionalIDs 注释其实体容器,请参阅 [OData-VocCore] 。
实体引用使用实体的实体 ID 来引用实体。
4.2 读取 URL 和编辑 URL
实体的读取 URL 是可用于读取实体的 URL。
实体的编辑 URL 是可用于更新或删除实体的 URL。
属性的编辑 URL 是带有包含属性路径的附加段的实体的编辑 URL。
强烈建议服务使用 OData-URL 中定义的实体规范 URL 作为实体的读取 URL 和编辑 URL,并在规范 URL 中附加实体类型的强制转换段(如果类型为实体是从实体集的声明类型派生的。然而,客户端不能采用这一约定,并且必须根据适当的格式使用有效负载中指定的链接,因为两个 URL 可能彼此不同,或者其中一个或两个 URL 可能与约定不同。
4.3 瞬态实体
瞬态实体是“动态计算”的实体类型的实例,并且仅存在于单个有效负载中。它们不能被重新读取或更新,因此既不具有稳定的实体 ID,也不具有读取 URL 或更新 URL。
4.4 默认命名空间
对 URL 中的操作、函数和类型的引用通常需要在操作、函数或类型的名称前加上定义它的命名空间或别名。此命名空间限定可以区分架构中类似命名的元素,或者具有相同名称的属性和绑定函数、操作或类型。
服务可以通过 [OData-VocCore] 中定义的 Core.DefaultNamespace 术语定义一个或多个默认命名空间。默认命名空间中的函数、操作和类型可以在具有或不具有命名空间或别名限定的 URL 中引用。
服务设计者应确保所有默认命名空间中架构子级的唯一性,并应避免使用与类型的结构或导航属性相同的名称来命名绑定函数、操作或派生类型。
在确实存在歧义的情况下,附加到结构化值的非限定段始终首先与结构化类型上定义的属性列表进行比较。如果不存在名称与非限定段匹配的已定义属性,或者前面的段表示集合或标量值,则接下来将其与任何默认命名空间中定义的任何绑定函数或操作的名称或派生类型名称进行比较。如果仍然不匹配,并且前面的段表示结构化值,则将其解释为动态属性。
服务可能不允许结构化值上的动态属性,这些属性的名称与默认命名空间中定义的绑定操作、函数或派生类型冲突。
如果默认名称空间的子级之间发生名称冲突,则行为未定义。我们鼓励通用客户端始终限定操作、函数和类型名称,以避免任何可能的歧义。
5 版本控制
版本控制使客户端和服务能够独立发展。OData 定义了协议和数据模型版本控制的语义。
5.1 协议版本控制
OData 请求和响应根据 OData-Version 标头进行版本控制。
OData 客户端在请求中包含 OData-MaxVersion 标头,以便指定可接受的最大响应版本。服务使用十进制比较,以小于或等于请求的 OData-MaxVersion 的最大支持版本进行响应。OData-Version 和 OData-MaxVersion 标头字段的语法在 [OData-ABNF] 中定义。
服务应该通过 [OData-VocCore] 中定义的 Core.ODataVersions 术语来通告支持的 OData 版本。
此版本的规范定义了 OData 版本值 4.0 和 4.01。仅适用于一个版本或另一个版本的内容会在文本中明确指出。
5.2 模型版本控制
OData 服务公开的数据模型定义了 OData 服务与其客户端之间的契约。服务只能在不破坏现有客户端的情况下扩展其模型。重大更改(例如删除属性、更改现有属性的类型、添加或删除关键属性或重新排序操作或函数参数)要求在新模型的不同服务根 URL 处提供新服务版本,或者使用 [OData-VocCore] 中定义的 Core.SchemaVersion 注释来版本其元数据。
对其元数据进行版本控制的服务必须根据 $schemaversion 系统查询选项支持特定于版本的请求。以下数据模型添加被认为是安全的,不需要服务对其入口点或架构进行版本控制。
- 添加可为空或具有默认值的属性;如果它与现有动态属性同名,则它必须与现有动态属性具有相同的类型(或基类型)
- 添加可为空或集合值的导航属性;如果它与现有动态导航属性同名,则它必须与现有动态导航属性具有相同的类型(或基本类型)
- 向模型添加新的实体类型
- 向模型添加新的复杂类型
- 添加新的实体集
- 添加一个新的单例
- 添加操作、函数、操作导入或函数导入
- 在现有参数之后添加可为空的操作参数
- 在现有参数后添加使用 Core.OptionalParameter 注释的操作或函数参数
- 添加类型定义或枚举
- 添加新术语
- 将任何注释添加到客户端不需要理解的模型元素以便与服务正确交互
客户应该为服务对其模型进行此类增量更改做好准备。特别是,客户端应该准备好接收服务先前未定义的属性和派生类型。
服务不应根据经过身份验证的用户更改其数据模型。如果数据模型依赖于用户或用户组,则在将完整模型与具有受限授权的用户可见的模型进行比较时,所有更改都必须是本节中定义的安全更改。
6 扩展性
OData 协议通过版本控制、约定和显式扩展点的组合支持用户驱动和版本驱动的可扩展性。
6.1 查询选项扩展性
请求 URL 中的查询选项可以控制服务如何处理特定请求。
OData 定义的系统查询选项可以选择以 “ \ ” 为前缀。服务可能支持 OData 规范中未定义的其他自定义查询选项,但它们不得以“ $ ”或“ @ ”字符开头,并且不得与服务支持的 OData 版本中定义的任何 OData 定义的系统查询选项冲突。
OData 服务不应要求在请求中指定任何查询选项。服务应该失败任何包含它们不理解的查询选项的请求,并且必须失败任何包含服务支持的本规范版本中定义的不支持的 OData 查询选项的请求。
在许多情况下,OData 服务返回 URL 来标识客户端稍后请求的资源。在可能的情况下,通过在 URL 的路径部分中提供所有标识信息来增强互操作性。但是,客户端应该做好准备,让此类 URL 包含自定义查询选项,并在将来对所识别的资源的请求中传播任何此类自定义查询选项。
6.2 负载扩展性
OData 根据特定格式支持有效负载的可扩展性。
无论格式如何,如果接收者需要理解附加内容以便根据指定的 OData-Version 标头正确解释有效负载,则不得存在附加内容。因此,客户端和服务必须准备好处理或安全地忽略OData-Version标头指定的有效负载版本中未明确定义的任何内容 。
6.3 动作/功能可扩展性
操作 和 函数 扩展了可以在服务或资源上执行或使用服务或资源执行的操作集。行动可能会产生副作用。例如,操作可用于修改数据或调用自定义操作。函数不能有副作用。可以从对资源进行寻址的 URL 或在filter](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionfilter) 或 [
orderby 系统查询选项的表达式中调用函数。
完全限定的操作和函数名称包括命名空间或别名前缀。Edm 、odata 和 geo 命名空间保留供本规范使用。
OData 服务必须使包含它不理解的操作或功能的任何请求失败。
6.4 词汇可扩展性
模式中定义的注释集包含词汇表。共享词汇表为 OData 提供了强大的扩展点。
元数据注释可用于定义元数据元素的附加特征或功能,例如服务、实体类型、属性、功能、操作或参数。例如,元数据注释可以定义特定属性的有效值范围。
实例注释可用于定义与特定结果、实体、属性或错误相关的附加信息;例如,某个属性对于特定实例是否是只读的。
当注释适用于类型的所有实例时,鼓励服务在元数据中指定注释,而不是在负载的每个实例中重复。如果在元数据和实例级别定义了相同的注释,则实例级别的注释将覆盖在元数据级别指定的注释。
服务不得要求客户端理解自定义注释才能准确解释响应。
OData 定义了一个核心 词汇表,其中包含一组描述行为方面的基本术语以及可用于定义其他词汇表的术语;请参阅 [OData-VocCore] 。
6.5 报头字段扩展性
OData 定义了某些 HTTP 请求和响应标头的语义。支持 OData 版本的服务符合本规范为该版本定义的标头的处理要求。
各个服务可以定义自定义标头。这些标头不得以 OData 开头。向服务发出请求时,自定义标头应该是可选的。服务不得要求客户端理解自定义标头才能准确解释响应。
6.6 格式扩展性
OData 服务必须支持 [OData-JSON] ,并且可以支持请求和响应正文的其他格式。
7 格式
客户端可以通过 [RFC7231] 中定义的 Accept 标头或通过系统查询选项 $format 请求特定的响应格式。
如果请求中同时指定了 Accept 标头和 format 系统查询选项, 则必须使用
format 查询选项中指定的值。
如果服务不支持请求的格式,则会回复 406 Not Acceptable 错误响应。
服务应该通过使用术语“功能”注释其实体容器来在元数据文档中宣传其支持的格式。SupportedFormats ,如 [OData-VocCap] 中定义,列出所有可用格式和支持的格式参数的组合。
元数据文档的 JSON 和 XML 表示的媒体类型在“元数据文档请求”部分中描述。
格式规范 [OData-JSON] 描述非元数据请求和响应的媒体类型和格式参数。
对于非元数据请求,如果 Accept 标头和 $format 查询选项均未指定,则服务可以响应任何格式的请求。
客户端库必须保留 JSON 响应中数组中对象的顺序,以及 XML 响应(包括 CSDL 文档)中文档顺序中的元素。
8 标头字段
OData 围绕以下请求和响应标头定义语义。可以指定其他标头,但在 OData 中没有定义唯一的语义。
8.1 通用头文件
以下标头在 OData 请求和响应之间很常见。
8.1.1 标头内容类型
非空单个请求或响应正文的格式(单独或在批处理中)必须在 请求或响应的Content-Type标头中指定。例外情况是,如果主体表示媒体实体或流属性的媒体流,在这种情况下,应该存在 Content-Type 标头。
指定的格式可以包括格式参数。客户端必须准备好服务返回 OData 中未定义的自定义格式参数,并且不应期望此类格式参数可以被忽略。自定义格式参数不得以“odata”开头,并且服务不得要求通用 OData 使用者理解自定义格式参数以便正确解释有效负载。
有关 Content-Type 标头中格式参数的格式特定详细信息,请参阅 [OData-JSON] 。
8.1.2 标头内容编码
如 [RFC7231] 中所定义, Content-Encoding 头字段用作媒体类型的修饰符(如 Content-Type 中所示)。当存在时,其值指示已将哪些附加内容编码应用于实体主体。
服务可以使用带有术语 Capability .AcceptableEncodings 的注释来指定可接受的内容编码列表,请参阅 [OData-VocCap] 。
如果 在批处理中的单个请求或响应上指定了 Content-Encoding 标头,则它指定该单个请求或响应的编码。不包含 Content-Encoding 标头的各个请求或响应将继承整个批量请求或响应的编码。
8.1.3 标题内容-语言
根据 [RFC7231] 中的定义 , 请求或响应可以包含 Content-Language 标头,以指示所附消息正文的目标受众的自然语言。OData 不会通过 HTTP 添加任何额外的要求 来包含 Content-Language 。OData 服务可以使用术语 Core.IsLanguageDependent 来注释其内容取决于内容语言的模型元素,请参阅 [OData-VocCore] 。
如果在批处理中的单个请求或响应上指定了 Content-Language 标头,则它指定该单个请求或响应的语言。不包含 Content-Language 标头的各个请求或响应将继承整个批处理请求或响应的语言。
8.1.4 标头内容长度
根据 [RFC7230] 中所定义的 , 当消息的长度可以在传输之前确定时,请求或响应应该包含Content-Length 标头。OData 不会通过 HTTP 添加任何额外的写入 Content-Length 的要求。
如果在批处理中的单个请求或响应上指定了 Content-Length 标头,则它指定该单个请求或响应的长度。
8.1.5 标头 OData 版本
OData 客户端应该在请求中使用 OData-Version 标头来指定用于生成请求负载的协议版本。
如果存在于请求中,服务必须根据指定协议版本中定义的规则解释请求有效负载,或者使用 4xx 响应代码使请求失败。
如果请求中未指定,则服务必须假设请求负载是使用 OData-MaxVersion 的最小值(如果指定)和服务理解的协议的最大版本生成的。
OData 服务必须在响应中包含 OData-Version 标头,以指定用于生成响应负载的协议版本。客户端必须根据指定协议版本中定义的规则解释响应负载。 请求和响应有效负载是独立的,并且根据上述规则可能具有不同的 OData-Version标头。
有关更多详细信息,请参阅版本控制。
如果 在批次内的单个请求或响应上指定 OData-Version 标头,则它指定该单个请求或响应的 OData 版本。不包含 OData-Version 标头的各个请求或响应将继承整个批处理请求或响应的 OData 版本。此 OData 版本通常不会在批次内发生变化。
8.2 请求头
除了 Common Headers 之外,客户端还可以指定以下请求标头的任意组合。
8.2.1 标头接受
根据 [RFC7231] 中所定义的,客户端可以使用接受 标头指定一组接受的格式。
服务必须拒绝指定未知或不支持的格式参数的格式。
如果 Accept 标头中指定的媒体类型包含字符集 格式参数,并且请求还包含 Accept-Charset 标头,则必须使用 Accept-Charset 标头。
如果 Accept 标头中指定的媒体类型不包含字符集格式参数,则 响应的 Content-Type 标头不得包含字符 集格式参数。
服务不应该向 Accept 标头中未指定的 Content-Type 参数添加任何格式参数。
如果 在批处理中的单个请求上指定 Accept 标头,则它指定该单个请求的可接受格式。批次中不包含 Accept 标头的请求将继承整个批次请求的可接受格式。
8.2.2 标头接受字符集
根据 [RFC7231] 中所定义的,客户端可以使用 Accept-Charset 标头指定可接受的字符集集。
如果在批处理中的单个请求上指定 Accept-Charset 标头,则它指定该单个请求可接受的字符集。批处理中不包含 Accept-Charset 标头的请求将继承整个批处理请求的可接受字符集。
8.2.3 标头接受语言
根据 [RFC7231] 中的定义,客户端可以使用 Accept-Language 标头指定一组接受的自然语言。
如果在批处理中的单个请求上指定了 Accept-Language 标头,则它指定该单个请求的可接受语言。批处理中不包含 Accept-Language 标头的请求将继承整个批处理请求的可接受语言。
8.2.4 标头 If-Match
根据 [RFC7232] 中的定义,客户端可以在 GET、POST、 PUT、PATCH 或 DELETE 请求中包含If-Match 标头。If-Match 请求标头的值 必须是先前为资源检索的 ETag 值,或者*匹配任何值。
如果对现有资源的操作需要 ETag(请参阅 [OData-VocCore] 中的术语 Core.OptimisticConcurrency 和 [OData-VocCap] 中的Capability.NavigationPropertyRestriction 类型的属性OptimisticConcurrencyControl )并且客户端未指定 If-Match 请求标头在数据修改请求或调用绑定到资源的操作的操作请求中,服务以 428 需要前提条件进行响应,并且必须确保请求的结果不会发生可观察到的更改。
如果存在,则仅当指定的 ETag 值与目标资源的当前 ETag 值匹配时,才必须处理请求。发送带有弱 ETag 的 ETag 标头(仅依赖于与表示无关的实体状态)的服务必须使用弱比较函数,因为它足以防止意外覆盖。这是与 [RFC7232] 的偏差。
如果该值与数据修改请求 或操作请求的资源的当前 ETag 值不匹配,则服务必须以 412 Precondition Failed 进行响应,并且必须确保请求的结果不会发生可观察到的更改。在 upsert 的情况下,如果寻址实体不存在,则认为提供的 ETag 值不匹配。
PUT 或 PATCH 请求中值为*的 If -Match 标头会导致 upsert 请求被处理为更新而不是插入。
If -Match 标头不得在批量请求上指定,但可以在批量内的各个请求上指定。
8.2.5 标头 If-None-Match
根据 [RFC7232] 中的定义,客户端可以在 GET、POST、PUT、PATCH 或 DELETE 请求中包含 If-None-Match 标头。If-None-Match 请求头的值必须是先前为资源检索的 ETag 值,或者*。
如果存在,则仅当指定的 ETag 值与资源的当前 ETag 值不匹配时,才必须使用弱比较函数(参见 [RFC7232] )处理请求。如果该值与资源的当前 ETag 值匹配,则对于GET请求,服务应该响应 304 Not Modified,对于 Data Modification Request 或 Action Request ,服务必须响应 412 Precondition Failed,并且必须确保没有请求的结果会发生可观察到的变化。
PUT 或 PATCH 请求中值为*的 If -None-Match 标头会导致 upsert 请求被处理为 insert 而不是 update。
If -None-Match 标头不得在批量请求上指定,但可以在批量内的各个请求上指定。
8.2.6 标头隔离 (OData-Isolation)
Isolation 标头指定当前请求与外部更改的隔离。此标头唯一支持的值是 snapshot。
如果服务不支持 Isolation:snapshot 并且在请求中指定了此标头,则服务不得处理该请求,并且必须以 412 Precondition Failed 进行响应。
快照隔离可保证为请求返回的所有数据(包括批次中的多个请求或 跨多个页面检索的结果)在单个时间点上保持一致。只有在请求内进行的数据修改(例如,通过同一批次内的数据修改请求)才可见。效果就好像请求生成了所提交数据的“快照”,就像请求开始时所存在的一样。
可以在单个或批量请求上指定隔离标头。如果在批次上指定,则该值将应用于批次内的所有语句。
快照内返回的下一个链接返回与初始请求相同的快照内的结果;客户端不需要在每个单独的页面请求上重复标头。
Isolation 标头对除下一个链接之外 的链接没有影响。导航链接、读取链接和编辑链接返回数据的当前版本。
如果消费者尝试点击引用不再可用的快照的下一个链接,服务将返回 410 Gone 或 404 Not Found 。
Isolation 标头的语法在 [OData-ABNF] 中定义。
服务可以使用带有术语 Capability.IsolationSupported 的注释来指定对 Isolation:snapshot 的支持,请参阅 [OData-VocCap] 。
注意:Isolation 标头在 OData 版本 4.0 中被命名为 OData-Isolation。支持 Isolation 标头的服务还应该支持 OData 4.0 客户端的 OData-Isolation ,并且客户端应该使用 OData-Isolation 来与 OData 4.0 服务兼容。如果在同一请求中指定了 Isolation 和 OData-Isolation 标头,则应使用 Isolation 标头的值。
8.2.7 标头 OData-MaxVersion
客户端应该指定 OData-MaxVersion 请求标头。
如果指定,服务必须生成一个响应,其中最大支持的 OData-Version 小于或等于指定的 OData-MaxVersion。
如果未指定 OData-MaxVersion,则服务应随着时间的推移返回具有相同 OData 版本的响应,并将请求解释为 OData-MaxVersion 等于服务在其初始发布时支持的最大 OData 版本。
如果在批次内的单个请求上指定 OData-MaxVersion 标头,则它指定该单个请求的最大 OData 版本。不包含 OData-MaxVersion 标头的各个请求将继承整个批处理请求或响应的最大 OData 版本。最大 OData 版本通常不会在批次内发生变化。
有关更多详细信息,请参阅版本控制。
8.2.8 标头偏好
Prefer 标头,如 [RFC7240] 中定义 ,允许客户端向服务请求某些行为。服务必须忽略服务不支持或未知的首选项值。
Prefer 标头的值是以逗号分隔的首选项列表。以下小节描述了首选项,其在 OData 中的含义由本规范定义。
为了响应包含 Prefer 标头的请求,服务可以返回 Preference-Applied 和 Vary 标头。
8.2.8.1 首选项 allow-entityreferences ( odata.allow-entityreferences )
allow-entityreferences 首选项表示允许服务在相同响应中返回实体引用(例如,在序列化多对多关系的展开结果时),以代替至少具有请求的属性的先前返回的实体(例如,在序列化多对多关系的展开结果时)。如果 allow-entityreferences 没有在请求中指定,除非本文档中的其他规则明确定义,否则服务不能以请求的实体替换实体引用。allow-entityreferences 首选项的语法在 [OData-ABNF] 中定义。
在服务应用 allow-entityreferences 首选项的情况下, 它必须包含一个包含 allow-entityreferences 首选项的 Preference-Applied 响应头,以指示可以返回实体引用来代替先前返回的实体。
如果 在批处理中的单个请求上指定了 allowed-entityreferences 首选项,则它会指定该单个请求的首选项。批处理中不包含 allowed-entityreferences 首选项的各个请求将继承整个批处理请求的首选项。
注意:allow-entityreferences 首选项 在 OData 版本 4.0 中被命名为 odata.allow-entityreferences 。支持 allow-entityreferences 首选项的服务还应该支持 OData 4.0 客户端的 odata.allow-entityreferences ,并且客户端应该使用 odata.allow-entityreferences 来与 OData 4.0 服务兼容。
8.2.8.2 回调优先级( odata.callback )
对于客户端使用服务返回的链接轮询附加信息的场景,客户端可以指定回调首选项以请求服务在数据可用时通知客户端。
可以指定回调优先级:
回调优先级必须包含参数 url,其值为 OData 服务在数据可用时被调用的回调端点的 URL。回调优先级的语法在 [OData-ABNF] 中定义。
对于基于 HTTP 的回调,OData 服务 针对指定的 URL 执行 HTTP GET 请求。
支持回调的服务 应该支持通过 HTTP 通知客户端。服务可以使用功能来通告回调支持。CallbackSupported 注释术语在 [OData-VocCap] 中定义。
如果服务应用回调首选项,它必须 在 Preference-Applied 响应头中 包含回调首选项。
当回调首 选项应用于异步请求时,OData 服务在完成请求处理后将调用回调端点。然后,可以使用之前返回的 202 Accepted 响应的 Location 标头中返回的状态监视器资源来检索异步执行的请求的结果。
当在对 delta 链接的 GET 请求上指定回调优先级,并且没有可用的更改时,OData 服务返回一个带有 Location 头的 202 已接受响应,其中指定用于检查未来更新的 delta 链接。然后,OData 服务在有新的更改可用时调用指定的回调端点。
当在对 delta 链接的 GET 请求上指定回调优先级,并且没有可用的更改时,OData 服务返回一个带有 Location 头的 202 已接受响应,其中指定用于检查未来更新的 delta 链接。然后,OData 服务在有新的更改可用时调用指定的回调端点。
- 如果服务同步处理请求,并且没有可用的更新,则响应与未指定 respond-async 相同,并导致如上所述的响应。
- 如果服务异步处理请求,那么它会像对任何其他异步请求一样响应一个指定状态监视资源 URL 的 202 已接受响应。一旦服务完成对 delta 链接资源的异步请求处理,如果有更改,它会调用指定的回调端点。 如果没有更改,服务应该等待通知客户端,直到有更改为止。 一旦收到通知,客户端使用之前返回的 202 已接受响应中的 Location 头中的状态监视资源来检索结果。 如果在处理初始请求后没有可用的更新,结果将不包含更新,客户端可以使用结果中的 delta 链接来检索此后变为可用的更新。
如果消费者在多个请求中指定了同一个 URL 作为回调端点,一次可用的任何请求的数据就绪后,服务可以将它们合并为单个通知。然而,消费者必须准备好处理它请求次数多的通知。
示例 2:使用 HTTP 回调端点接收通知
Prefer: callback; url="http://myserver/notfication/token/12345"
如果在批处理中的单个请求上指定了回调优先级,那么它指定了用于跟踪该单个请求的更改的回调。 如果在批处理上指定回调优先级,那么它指定了用于批处理的异步响应的回调。
注意:回调优先级在 OData 4.0 中名为 odata.callback。支持回调优先级的服务也应支持 odata.callback 以便 OData 4.0 客户端,客户端应该为了与 OData 4.0 服务的兼容使用 odata.callback。如果在同一个请求中同时指定了 callback 和 odata.callback 优先级,应使用 callback 优先级的值。
8.2.8.3 继续执行错误首选项 (odata.continue-on-error)
在批处理请求中,继续执行错误首选项用于指定在批处理中遇到返回错误的请求时,服务是否继续处理批处理中的其他请求(如果使用隐式或显式值为true指定),或者停止进一步处理(如果使用显式值为false指定)。继续执行错误首选项的语法在 [OData-ABNF] 中定义。
继续执行错误首选项也可以用于增量更新、基于集合的更新或基于集合的删除,以请求服务在收到错误后继续尝试处理更改。
服务可以使用带有术语 Capability.BatchContinueOnErrorSupported 的 注释来指定对错误时继续首选项的支持,请参阅 [OData-VocCap] 。
继续执行错误首选项不应该应用于批处理中的单个请求。
注意: 在 OData 4.0 版本中,继续执行错误首选项被命名为 odata.continue-on-error。支持继续执行错误首选项的服务也应支持 OData 4.0 客户端的 odata.continue-on-error,客户端应该使用 odata.continue-on-error 与 OData 4.0 服务兼容。
8.2.8.4 包含注释首选项(odata.include-annotations)
数据或元数据请求中的包含注释首选项用于指定客户端请求包含在响应中(如果适用)的注释集。
include-annotations 首选项的值是一个逗号分隔的命名空间限定的词条名或词条名模式列表,用于包括或排除,* 作为名称段的通配符。词条名和词条名模式可以可选地后跟一个井号(#)字符和一个注释限定符。include-annotations 首选项的完整语法在 [OData-ABNF] 中定义。
最具体的标识符始终优先,显式名称优先于名称模式,较长模式优先于较短模式。如果请求排除和包含相同的标识符值,则行为未定义;服务可以返回或省略指定的词汇表,但不得引发异常。
示例 3: 请求返回元数据文档中的所有注释的Prefer标头
首选:include-annotations="*"
示例 4: 请求不返回注释的Prefer标头
首选:include-annotations="-*"
示例 5:Prefer 标头请求返回“display”命名空间下定义的所有注释(递归地)
首选:include-annotations="display.*"
示例 6:Prefer标头请求返回显示命名空间 内带有术语名称subject 的 注释
首选:include-annotations="display.subject"
示例 7:Prefer 标头请求返回在“display”命名空间下(递归地)定义的带有限定符“tablet”的所有注释
首选:include-annotations="display.*#tablet"
包含注释首选项只是对服务的提示。服务可以忽略该首选项,并可以自由决定是否返回包含注释首选项中未指定的注释。
如果客户端在请求中指定了 include-annotations 首选项,服务应该在适用的响应中包含一个 Preference-Applied 响应头,其中包含实际包含在响应中的注释的 include-annotations 值。此值可能与请求中的 Prefer 头中请求的注释不同。
如果在批处理中的单个请求上指定了 include-annotations 首选项,那么它指定了该单个请求的首选项。批处理中不包含 include-annotations 首选项的单个请求继承批处理请求的整体首选项。
注意:在 OData 4.0 版本中,include-annotations 首选项被命名为 odata.include-annotations。支持 include-annotations 首选项的服务也应该支持 OData 4.0 客户端的 odata.include-annotations,客户端应使用 odata.include-annotations 与 OData 4.0 服务兼容。如果在同一请求中同时指定了 include-annotations 和 odata.include-annotations 首选项,应使用 include-annotations 的值。
8.2.8.5 首选项 maxpagesize ( odata.maxpagesize )
maxpagesize 首选项用于请求响应中的每个集合包含的项目数不超过指定为此首选项的正整数值。maxpagesize 首选项的语法在 [OData-ABNF] 中定义。
示例 8:对客户及其订单的请求将导致响应包含一个包含客户实体的集合,以及针对每个客户的一个单独的包含订单实体的集合。客户端可以指定 maxpagesize=50,以请求每页结果最多包含 50 个客户,每个客户最多 50 个订单。
如果结果中的集合包含的内容超过指定的 maxpagesize,则该集合应该是结果的部分集,并带有指向下一页结果的下一个链接。客户端可以为该首选项指定不同的值,每个请求都遵循下一个链接。
在上面给出的示例中,如果客户数量超过 50 个,结果页面应包含客户集合的下一个链接,以及包含超过 50 个实体的所有返回订单集合的附加下一个链接。
如果客户端在请求中指定了 maxpagesize 首选项,并且服务通过服务器驱动的分页 限制响应中集合中的项目数,则服务可以包含一个包含 maxpagesize 首选项和最大页面大小的 Preference-Applied 响应标头应用。该值可能与客户端请求的值不同。
maxpagesize 首选项不应应用于批量请求,但可以应用于批量内的单个请求。
注意:maxpagesize 首选项名为 odata。 OData 版本 4.0 中的 maxpagesize 。支持 maxpagesize 首选项的服务也应该支持 odata。OData 4.0 客户端的 maxpagesize 和客户端应该使用 odata。maxpagesize 与 OData 4.0 服务兼容。如果 maxpagesize 和 odata. maxpagesize 首选项在同一请求中指定,应该使用 maxpagesize 首选项 的值。
8.2.8.6 偏好 省略值
省略值首选项指定可以从响应负载中省略的值。有效值为null或默认值。
如果指定了 nulls,则服务可以从响应中省略包含 null 值的属性,在这种情况下,它必须使用 omit-values=nulls指定 Preference-Applied 响应标头。
如果指定了默认值,则服务可以从响应中忽略包含默认值的属性,包括没有其他定义的默认值的属性的空值。对于定义了非空默认值的属性,必须包含空值。如果服务省略默认值,它必须使用 omit-values=defaults 指定 Preference-Applied 响应头。
具有实例注释的属性不受此首选项的影响,并且如果在没有此首选项的情况下包含它们,则必须将其包含在有效负载中。客户端不得尝试为存在实例注释且不存在属性值的属性重建 null 或默认值,例如,如果该属性由于权限而被省略并已替换为实例注释 Core.Permissions 和 None 的值,请参阅 [OData-VocCore] 。
具有空值或默认值的属性必须包含在增量负载中(如果已修改)。
对 POST 操作的响应必须包括任何未设置为其默认值的属性,对 PUT/PATCH 操作的响应必须包括其值在操作过程中发生更改的任何属性。
省略值首选项不会影响请求负载。
8.2.8.7 偏好 return=representation 和 return=minimal
return =representation 和 return=minimal 首选项在 [RFC7240] 中定义。
在 OData 中,return=representation 或 return=minimal 被定义为与 POST 、PUT 或 PATCH数据修改请求 或 Action Request一起使用。在 GET 或 DELETE 请求中指定 return=representation 或 return=minimal 首选项没有任何效果。
批处理中的单个数据修改请求或操作请求允许使用return=representation或return=minimal首选项,但受到相同的限制,但如果在批处理请求本身上指定,则应返回4xx 客户端错误。
return=minimal的首选项 要求服务调用请求但不在响应中返回内容。服务可以通过返回204 No Content 来应用此首选项,在这种情况下,它可以包含一个包含return=minimal首选项 的Preference-Applied 响应头。
return=representation 的首选项请求服务调用该请求并返回修改后的资源。服务可以通过在响应正文中返回成功修改的资源的表示来应用此首选项,该表示根据为请求的格式指定的规则进行格式化。在这种情况下,服务可以包含一个Preference-Applied 响应头,其中包含return=representation 首选项。
返回首选项 不应该应用于批量请求,但可以应用于批量内的单个请求。
8.2.8.8 优先响应异步
响应异步首选项,如 [RFC7240] 中定义,允许客户端请求服务异步处理请求。
如果客户端在请求中指定了 respond-async ,则服务可以异步处理请求并返回 202 Accepted 响应。
响应异步首选项可以用于批处理请求,在这种情况下,它适用于整个批处理请求,而不是批处理请求中的各个请求。
在服务应用响应异步首选项的情况下, 它必须包含一个包含响应异步首选项的 Preference-Applied 响应标头 。
服务可以使用带有术语 Capability.AsynchronousRequestsSupported 的注释来指定对响应异步首选项的支持,请参阅 [OData-VocCap] 。
示例 9:接收以下标头的服务可能会选择响应
首选:响应异步,等待=10
8.2.8.9 偏好跟踪更改( odata.track-changes )
跟踪更改首选项用于请求服务返回增量链接,该链接随后可用于获取对此结果的更改(增量)。跟踪更改 首选项的语法在 [OData-ABNF] 中定义。
对于分页结果,必须在初始请求中指定首选项。 如果应用于下一个链接,服务必须忽略跟踪更改首选项。
增量链接必须仅在结果的最后一页上返回,而不是下一个链接。
该服务在响应的第一页中包含一个 Preference-Applied 响应标头,其中包含跟踪更改 首选项,以表明正在跟踪更改。
服务可以使用带有术语 Capability.ChangeTracking 的 注释来指定对跟踪更改首选项的支持,请参阅 [OData-VocCap] 。
跟踪更改首选项不应应用于批量请求,但可以应用于批量内的单个请求。
注意:在 OData 版本 4.0 中,跟踪更改 首选项被命名为odata .track-changes 。支持跟踪更改 首选项的服务也应该支持odata。OData 4.0 客户端的跟踪更改 以及客户端应该使用odata。 跟踪与 OData 4.0 服务兼容性的更改。
8.2.8.10 优先等待
等待首选项,如 [RFC7240] 中定义,用于建立时间长度的上限(以秒为单位),客户端在收到请求后准备等待服务同步处理请求。
如果还指定了 respond-async 首选项,则客户端请求服务在指定的时间长度后异步响应。
如果 未指定响应异步首选项,则服务可以将等待解释为在指定时间段后超时的请求。
如果在批处理中的单个请求上指定等待首选项,则它指定等待该单个请求的最长时间。如果在批次上指定等待首选项,则它指定等待整个批次的最长时间。
8.3 响应头
除了 Common Headers 之外,以下响应标头在 OData 中也定义了含义。
8.3.1 异步结果头
4.01服务 必须在来自状态监视器资源的200 OK响应中包含AsyncResult标头,以便指示异步执行请求的最终HTTP 响应状态代码。
AsyncResult标头不应应用于批次中的各个响应。
8.3.2 标头 ETag
响应可以包含 ETag 标头,请参阅 [RFC7232] 。如果服务在修改资源时需要指定 ETag,则必须包含此标头。
服务必须支持在资源的后续数据请求的 If-None-Match 头中指定返回的 ETag 头的值。在对资源执行后续的数据修改请求或操作请求时,客户端必须在 If-Match 头中指定返回的 ETag 头的值或星号(*),以应用乐观并发控制来更新、删除或调用绑定到资源的操作。
由于 OData 允许使用多种格式来表示相同的结构化信息,所以服务应该使用只依赖表示独立实体状态的弱 ETag。强 ETag 在实体的表示形式发生变化时必须更改,所以它必须依赖响应的 Content-Type、Content-Encoding 以及可能的其他特征。
ETag 头也可以在元数据文档请求或服务文档请求的响应中返回,以允许客户端随后对元数据或服务文档进行有条件的请求。客户端也可以将从元数据文档请求返回的 ETag 头的值与响应中返回的元数据 ETag 值进行比较,以验证用于生成该响应的元数据的版本。
ETag 标头不应包含在整个批次响应中,但可以包含在批次内的各个响应中。
8.3.3 标题位置
必须在创建实体或创建媒体实体的请求的响应中返回 Location 头,以指定创建实体的编辑 URL,对于只读实体,则指定读取 URL。在返回 202 已接受的响应中也必须返回该头,以指定客户端可以用来请求异步请求状态的 URL。
Location标头不应包含在整个批次响应中,但可以包含在批次内的各个响应中。
8.3.4 标头 OData-EntityId
对创建或更新操作返回 204 无内容的响应必须包含一个 OData-EntityId 响应头。该头的值为请求所针对的实体的实体标识符。OData-EntityId 头的语法定义在 [OData-ABNF] 中。
OData - EntityID 标头不应包含在整个批处理响应中,但可以包含在批处理内的各个响应中。
8.3.5 标头 OData 错误
如果传输协议支持尾部标头(例如带有分块传输编码的 HTTP/1.1 或 HTTP/2),则带有流内错误的响应可以包括 OData-Error 尾部标头。
此尾随标头的值是根据 OData 响应格式的标准 OData 错误响应,经过适当编码以便在标头中传输,请参见 [OData-JSON] 等。
8.3.6 Preference-Applied 头
对指定 Prefer 头的请求的响应中,服务可以包含一个 Preference-Applied 头,如 [RFC7240] 中定义的那样,指定请求中的单个偏好如何处理。
Preference-Applied 头的值是一个应用于响应的首选项的逗号分隔列表。有关单个首选项的更多信息,请参阅 Prefer 头。
如果 Preference-Applied 头在批处理内的单个响应上指定,则它指定应用于该单个响应的首选项。如果 Preference-Applied 头在批处理响应上指定,则它指定应用于整个批处理的首选项。
8.3.7 Retry-After 头
服务可以在 202 已接受和 3xx 重定向响应中包含 Retry-After 头,如 [RFC7231] 中定义的那样。
Retry-After 头指定了客户端在重试请求或发出 Location 头返回的值所指向资源的请求之前应等待的时间间隔,以秒为单位。
8.3.8 Vary 头
如果响应根据响应的 OData-Version 而有所不同,则服务必须在 Vary 头中列出 OData-MaxVersion 请求头字段,以允许正确缓存响应。
如果响应根据应用的首选项(allow-entityreferences、include-annotations、omit-values、return)而有所不同,则服务必须在 Vary 头中列出 Prefer 请求头字段,以允许正确缓存响应。
另外,服务器可以包含一个特殊值 * 的 Vary 头,如 [RFC7231] 第 8.2.1 节中定义的那样。请注意,这将使代理无法缓存响应,参见 [RFC7240]。
9 常见的响应状态代码
OData 服务可以使用适合请求的任何有效 HTTP 状态代码来响应任何请求。服务在选择 HTTP 状态代码时应该尽可能具体。
以下代表最常见的成功响应代码。在某些情况下,服务可以响应更具体的成功代码。
9.1 成功响应
以下响应代码代表请求成功。
9.1.1 响应代码 200 OK
不创建资源的请求如果成功完成并且资源的值不为null ,则返回200 OK。在这种情况下,响应正文必须包含请求 URL 中指定的资源的值。
9.1.2 响应代码 201 Created
成功创建资源的创建实体、创建媒体实体或调用操作的请求应返回 201 Created。在这种情况下,响应体必须包含所创建的资源。
9.1.3 响应代码 202 Accepted
202 Accepted 表示数据服务请求已被接受,但尚未完成异步执行。异步请求和异步批处理请求的异步处理方式在相关章节中定义。
9.1.4 响应代码 204 No Content
如果请求的资源值为 null,或者服务应用了 return=minimal 首选项,则请求返回 204 No Content。在这种情况下,响应体必须为空。
如 [RFC7231] 中所定义,返回 204 No Content 的数据修改请求可以包含 ETag 头,该头的值反映数据修改的结果,但仅当客户端可以在不实际接收资源的情况下“已知”资源的新表示形式时才如此。对于 PUT 请求,这意味着对应 200 OK 或 201 Created 响应的响应体与请求体相同,即没有对请求体中的值进行服务器端修改、没有计算服务器端值等。对于 PATCH 请求,这意味着对应 200 OK 或 201 Created 响应的响应体由请求体中的所有值以及(对于请求体中未发送的值)与 PATCH 请求中的 If-Match 头的值对应的服务器端值组成,即客户端“已知”的前一个值。
9.1.5 响应代码 3xx 重定向
如 [RFC7231] 中所述,3xx 重定向表示客户端需要采取进一步操作才能满足请求。在这种情况下,响应应当包含适当的 Location 头,包含可以获得结果的 URL;它可能包括 Retry-After 头。
9.1.6 响应代码 304 Not Modified
如 [RFC7232] 中所述,当客户端执行包含 If-None-Match 头的 GET 请求且内容未更改时,返回 304 Not Modified。在这种情况下,响应不应包含其他头,以防止实体主体与更新的头之间的不一致。
服务必须确保任何返回 304 Not Modified 的请求都不会对服务的状态产生可观察的更改。
9.2 客户端错误响应
4xx范围内的错误代码表示客户端错误,例如格式错误的请求。
服务必须确保任何返回错误状态代码的请求不会导致服务状态发生明显的变化。
在为错误代码定义了响应主体的情况下,错误主体是为适当的格式定义的。
9.2.1 响应代码 404 Not Found
404 Not Found表示请求URL指定的资源不存在。响应正文可以提供附加信息。
9.2.2 响应代码 405 Method Not Allowed
405 Method Not Allowed 表示请求 URL 指定的资源不支持请求方法。在这种情况下,响应必须包含 Allow 头,其中包含 [RFC7231] 中定义的请求资源的有效请求方法列表。
9.2.3 响应代码 406 Not Acceptable
406 Not Acceptable 表示请求 URL 指定的资源没有可为客户端接受的当前表示形式,根据请求头 Accept、Accept-Charset 和 Accept-Language,且服务不愿提供默认表示形式。
9.2.4 响应代码 410 Gone
410 Gone 表示请求的资源不再可用。如果客户端等待太长时间才遵循 delta 链接或状态监视资源链接,或者对使用快照隔离请求的集合的 next 链接,就可能发生这种情况。
9.2.5 响应代码 412 Precondition Failed
如 [RFC7232] 中所定义,412 Precondition Failed 表示客户端执行了条件请求,但资源不满足条件。服务必须确保请求不会导致可观察的更改。
9.2.6 响应代码 424 Failed Dependency
424 Failed Dependency表示由于依赖失败而导致请求未执行;例如,批次中依赖于失败请求的请求。
9.3 服务器错误响应
如 [RFC7231] 中所定义,5xx 范围中的错误代码表示服务错误。
9.3.1 响应代码 501 Not Implemented
如果客户端请求 OData 服务未实现的功能,则服务会响应501 Not Implemented,并且应该包含描述未实现的功能的响应正文。
9.4 错误响应正文
错误响应正文的表示形式特定于格式。它至少包含以下信息:
- code:必需的非空非空的语言无关字符串。其值为服务定义的错误代码。此代码用作响应中指定的 HTTP 错误代码的子状态。
- message:描述错误的必需的非空非空的语言相关人类可读字符串。Content-Language 头必须包含与 message 中的语言对应的 [RFC5646] 中的语言代码。
- target:表示错误目标的可选可为空字符串,例如出错的属性名称。
- details:可选的、潜在为空的结构化实例集合,具有遵循上述规则的代码、消息和目标。
- innererror:具有服务定义内容的可选结构化实例。
服务实现在考虑生产环境中的信息披露潜在安全问题时,应仔细考虑包含哪些信息。
9.5 流中的错误
如果服务在向客户端发送成功状态后遇到错误,则服务必须根据其内容类型使响应格式错误。客户端必须将整个响应视为错误。
如果受传输协议支持(例如带分块传输编码的 HTTP/1.1 或 HTTP/2),服务可以包含头 OData-Error 作为尾部头。
10. Context URL
Context URL 描述了 payload 的内容。它由 canonical metadata document 的 URL 和标识 metadata document 中相关部分的片段组成。Context URL 使得 response payload 可以“自包含”,允许接收方检索 metadata、解析引用和构造响应 payload 中某些优化格式省略的正规链接。
Request payload 一般不需要 context URL,因为 payload 的类型可以从 request URL 中确定。
有关 context URL 如何用于描述一个 payload 的详细信息,请参阅各个格式的相关章节。
下面的小节通过提供 context URL 模板来描述每个类别 payload 的 context URL 构造方式。Context URL 模板使用以下术语:
- {context-url} 是指向 $metadata 文档的 canonical 资源路径,
- {entity-set} 是实体集或包含导航属性的路径,
- {entity} 是实体的 canonical URL,
- {singleton} 是单例实体的 canonical URL,
- {select-list} 是所选属性、实例注解、函数和操作的可选括号内以逗号分隔的列表,
- {property-path} 是实体的结构属性的路径,
- {type-name} 是限定类型名称,
- {/type-name} 是包含从属类型或实现类型合格名称的可选类型转换段,前缀为正斜杠。
Context URL 的完整语法定义在 [OData-ABNF] 中。请注意,context URL 的语法独立于服务用于寻址单个实体的任何 URL 约定。
10.1 服务文档
Context URL 模板:
{context-url}
服务文档的 context URL 是服务的元数据文档 URL。
示例 10:资源 URL 和对应的 context URL
10.2 实体集合
Context URL 模板:
{context-url}#{entity-set}
{context-url}#Collection({type-name})
如果集合中的所有实体都是某个实体集的成员,则该实体集的名称就是 context URL 片段。
示例 11:资源 URL 和对应的 context URL
http://host/service/$metadata#Customers
如果实体是包含的,则 entity-set 是顶层实体集或单例,后跟包含实体的包含导航属性的路径。
示例 12:包含的实体的资源 URL 和对应的 context URL
http://host/service/Orders(4711)/Items
http://host/service/$metadata#Orders(4711)/Items
如果响应中的实体不绑定到单个实体集,例如来自没有实体集路径的函数或操作、没有指定实体集的函数导入或操作导入,或者没有导航属性绑定的导航属性,则 context URL 指定返回的实体集合的类型。
10.3 实体
Context URL 模板:
{context-url}#{entity-set}/$entity
{context-url}#{type-name}
如果响应或响应部分是一个实体集声明类型的单个实体,则在 context URL 后追加 /$entity。
示例 13:资源 URL 和对应的 context URL
http://host/service/Customers(1)
http://host/service/$metadata#Customers/$entity
如果实体是包含的,则 entity-set 是包含实体的包含导航属性的 canonical URL,例如 Orders(4711)/Items。
示例 14:包含实体的资源 URL 和对应的 context URL
http://host/service/Orders(4711)/Items(1)
http://host/service/$metadata#Orders(4711)/Items/$entity
如果响应不绑定到单个实体集,例如从没有实体集路径的函数或操作返回的实体,没有指定实体集的函数导入或操作导入,或者没有导航属性绑定的导航属性,则 context URL 指定返回实体的类型。
10.4 单例
Context URL 模板:
{context-url}#{singleton}
如果一个响应或响应部分是一个单例,它的名称就是 context URL 片段。
示例 15:资源 URL 和对应的 context URL
http://host/service/MainSupplier
http://host/service/$metadata#MainSupplier
10.5 派生实体集合
Context URL 模板:
{context-url}#{entity-set}{/type-name}
如果一个实体集仅由派生实体组成,则在 context URL 中添加类型转换段。
示例 16:资源 URL 和对应的 context URL
http://host/service/Customers/Model.VipCustomer
http://host/service/$metadata#Customers/Model.VipCustomer
10.6 派生实体
Context URL 模板:
{context-url}#{entity-set}{/type-name}/$entity
如果一个响应或响应部分是一个从实体集声明类型派生的单个实体类型,则在实体集名称后追加类型转换段。
示例 17:资源 URL 和对应的 context URL
http://host/service/Customers(2)/Model.VipCustomer
http://host/service/$metadata#Customers/Model.VipCustomer/$entity
10.7 项目化实体集合
Context URL 模板:
{context-url}#{entity-set}{/type-name}{select-list}
{context-url}#Collection({type-name}){select-list}
如果结果只包含一个子集的属性,则所选的定义的或动态的属性、实例注解、导航属性、函数和操作的括号内以逗号分隔的列表会追加到表示实体集合的 context URL。
无论请求 URL 中如何表示包含的结构属性(作为路径还是作为 select 选项),它们在 context URL 中都使用路径语法表示,如 OData 4.0 中定义的那样。
- 表示所有结构属性的列表的快捷方式。在实体集声明的类型(或类型转换段中指定的类型,如果有)派生的类型上定义的属性,用派生类型的限定名作为前缀,如 [OData-ABNF] 中定义的。
列表还包含明确选择或展开的实例注解。可以仅选择或展开实例注解,在这种情况下,结果中仅出现那些选择或展开的注解。请注意,仅在 include-annotations 首选项中指定的注解不出现在 context URL 中,也不会影响所选/展开的属性。
操作在 context URL 中使用命名空间或别名限定名表示。后缀带括号的函数名称表示特定重载,而不带括号的函数名称表示函数的所有重载。
OData 4.01 响应可以使用 {namespace}.* 的快捷模式表示集合中可用的所有绑定操作或函数,请参见系统查询选项 $select。
示例 18:资源 URL 和对应的 context URL
http://host/service/Customers?$select=Address,Orders
http://host/service/$metadata#Customers(Address,Orders)
10.8 投影实体
上下文 URL 模板:
{context-url}#{entity-set}{/type-name}{select-list}/$entity
{context-url}#{singleton}{select-list}
{上下文-url}#{类型名称}{选择列表}
如果单个实体包含属性的子集,则将所选定义或动态属性的逗号分隔列表、实例注释、导航属性、函数和操作附加到可选的类型转换段之后,并在附加 /$entity 之前附加到 {entity-set}。如果响应不是单个实体集的子集,则将 {select-list} 替代附加到返回实体的 {type-name}。
无论请求 URL 如何表示包含的结构属性(作为路径还是作为选择选项),它们在上下文 URL 中使用路径语法表示,如 OData 4.0 中定义的。
快捷符号 * 表示所有结构属性的列表。从实体集的类型派生的类型上定义的属性(或在类型转换段中指定的类型)以在 [OData-ABNF] 中定义的派生类型的限定名称作为前缀。请注意,展开的属性会自动包含在响应中。
列表还包含显式选择或扩展的实例注释。可以选择或扩展仅实例注释,这样只有那些选择或扩展的注释才会在结果中显示。请注意,仅在 include-annotations 首选项中指定的注释不会显示在上下文 URL 中,也不会影响所选/扩展的属性。
上下文 URL 中的操作使用命名空间或别名限定名称表示。带括号的函数名称表示特定的重载,而不带括号的函数名称表示函数的所有重载。
OData 4.01 响应中可以使用快捷模式 {namespace}.* 来表示返回实体可用的所有绑定操作或函数的列表,请参见系统查询选项 $select。
示例 19:资源 URL 和对应的上下文 URL
http://host/service/Customers(1)?$select=Name,Rating
http://host/service/$metadata#Customers(Name,Rating)/$entity
10.9 扩展实体集合
上下文 URL 模板:
{context-url}#{entity-set}{/type-name}{select-list}
{context-url}#Collection({type-name}){select-list}
对于 4.01 响应,如果显式扩展导航属性,则除了任何选定属性、导航属性、函数或操作的任何无后缀名称之外,以逗号分隔的属性列表还必须包含扩展属性的名称,后缀为所选或展开的扩展导航属性的任何属性的括号逗号分隔列表。如果展开的导航属性不包含嵌套的select或
expand,则展开的属性后缀为空括号。如果嵌套子级的扩展是递归的,则在导航属性名称和左括号之间插入一个加号 ( + )。
对于 4.0 响应,如果不包含嵌套的select或
expand,则从选择列表中省略带有括号后缀的扩展导航属性,但如果显式选择它,则必须仍然存在,没有后缀。
如果上下文 URL 仅包含扩展的导航属性(即,仅以括号为后缀的导航属性),则将隐式选择所有结构属性(与选择列表中没有列出属性相同)。
具有扩展引用的导航属性不会在上下文 URL 中表示。
示例 20:资源 URL 和相应的上下文 URL - 选择并展开
http://主机/服务/客户?$select=名称&$expand=地址/国家/地区
http://主机/服务/$metadata#Customers(名称、地址/国家/地区())
示例 21:资源 URL 和相应的上下文 URL – 展开$ref
http://host/service/Customers?$expand=Orders/$ref
http://主机/服务/$metadata#Customers
示例 22:资源 URL 和相应的上下文 URL – 使用$levels扩展
http://host/service/Employees/Sales.Manager?$select=DirectReports
&expand=DirectReports(
select=FirstName,LastName;$levels=4)
http://host/service/$metadata
#Employees/Sales.Manager(DirectReports,
DirectReports+(名字,姓氏))
10.10 扩展实体
上下文 URL 模板:
{context-url}#{entity-set}{/type-name}{select-list}/$entity
{context-url}#{singleton}{select-list}
{上下文-url}#{类型名称}{选择列表}
对于 4.01 响应,如果显式扩展导航属性,则除了任何选定属性、导航属性、函数或操作的无后缀名称之外,以逗号分隔的属性列表还必须包含扩展属性的名称,后缀为所选或展开的扩展导航属性的任何属性的括号逗号分隔列表。如果展开的导航属性不包含嵌套的select或
expand,则展开的属性后缀为空括号。如果嵌套子级的扩展是递归的,则在导航属性名称和左括号之间插入一个加号 ( + )。
对于 4.0 响应,如果不包含嵌套的select 或
expand,则从选择列表中省略带有括号后缀的扩展导航属性,但如果显式选择它,则必须仍然存在,没有后缀。
如果上下文 URL 仅包含扩展的导航属性(即,仅以括号为后缀的导航属性),则将隐式选择所有结构属性(与选择列表中没有列出属性相同)。
具有扩展引用的导航属性不会在上下文 URL 中表示。
示例 23:资源 URL 和相应的上下文 URL
http://host/service/Employees(1)/Sales.Manager?
expand=DirectReports(
select=名字,姓氏;$levels=4)
http://host/service/$metadata
#Employees/Sales.Manager(DirectReports+(名字,姓氏))/$entity
10.11 实体引用集合
上下文 URL 模板:
{context-url}#集合($ref)
如果响应是实体引用的集合,则上下文 URL 不包含所引用实体的类型。
示例 24:实体引用集合的资源 URL 和相应的上下文 URL
http://host/service/Customers('ALFKI')/Orders/$ref
http://host/service/$metadata#Collection($ref)
10.12 实体引用
上下文 URL 模板:
{上下文-url}#$ref
如果响应是单个实体引用,则$ref是上下文 URL 片段。
示例 25:资源 URL 和对应的上下文 URL 用于单个实体引用
http://host/service/Orders(10643)/Customer/$ref
http://host/service/$metadata#$ref
10.13 属性值
上下文 URL 模板:
{context-url}#{entity}/{property-path}{select-list}
{context-url}#{type-name}{select-list}
如果响应表示具有规范 URL 的实体的单个属性,则上下文 URL 指定实体的规范 URL 和该实体的结构属性的路径。路径必须包括为上一个段的预期类型派生类型上定义的属性的类型转换段。
如果属性值不包含显式或隐式选择的导航属性或操作,则 OData 4.01 响应可以使用较不具体的第二个模板。
示例 26:资源 URL 和对应的上下文 URL
http://host/service/Customers(1)/Addresses
http://host/service/$metadata#Customers(1)/Addresses
10.14 复杂类型或基元类型的集合
上下文 URL 模板:
{context-url}#Collection({type-name}){select-list}
如果响应是复杂类型或原始类型的集合,且不代表具有规范 URL 的实体的单个属性,则上下文 URL 指定该集合的完全限定类型。
示例 27:资源 URL 和对应的上下文 URL
http://host/service/TopFiveHobbies()
http://host/service/$metadata#Collection(Edm.String)
10.15 复杂类型或基元类型
上下文 URL 模板:
{context-url}#{type-name}{select-list}
如果响应是一个复杂类型或基元类型,而该类型不表示具有规范 URL 的实体的某个独立属性,那么上下文 URL 将指定结果的完全限定类型。
示例 28:资源 URL 和对应的上下文 URL
http://host/service/MostPopularName()
http://host/service/$metadata#Edm.String
10.16 操作结果
上下文 URL 模板:
{context-url}#{entity-set}{/type-name}{select-list}
{context-url}#{entity-set}{/type-name}{select-list}/$entity
{context-url}#{entity}/{property-path} {select-list}
{context-url}#Collection({type-name}){select-list}
{上下文-url}#{类型名称}{选择列表}
如果操作或函数的响应是实体集合或者是一个属于实体集的单个实体,那么上下文 URL 标识实体集。如果操作或函数的响应是单个实体的属性,那么上下文 URL 标识实体和属性。否则,上下文 URL 标识操作返回的类型。上下文 URL 将对应于前面的示例之一。
示例 29:资源 URL 和对应的上下文 URL
http://host/service/TopFiveCustomers()
http://host/service/$metadata#Customers
10.17 Delta 有效负载响应
上下文 URL 模板:
{context-url}#{entity-set}{/type-name}{select-list}/$delta
{context-url}#{entity}{select-list}/$delta
{context-url}#{entity}/{property-path}{select-list}/$delta
#$delta
Delta 响应的上下文 URL 是定义查询响应的上下文 URL 后面加上 /$delta。这包括单例、单值导航属性和集合值导航属性。
如果实体被包含,那么 {entity-set} 是顶级实体集后面加上包含实体的包含导航属性的路径。
示例 30:资源 URL 和对应的上下文 URL
http://host/service/Customers?$deltatoken=1234
http://host/service/$metadata#Customers/$delta
实体集合的更新请求正文的上下文 URL 仅仅是片段 #$delta。
10.18 Delta 有效负载响应中的项目
上下文 URL 模板:
{context-url}#{entity-set}/$deletedEntity
{context-url}#{entity-set}/$link
{context-url}#{entity-set}/$deletedLink
除了具有实体规范上下文 URL 的新实体或更改实体之外,增量响应还可以包含已删除实体、新链接和已删除链接。它们由相应的上下文 URL 片段标识。{entity-set}对应于已删除实体的集合,或添加或删除链接的源实体。
10.19 $all 响应
上下文 URL 模板:
{context-url}#Collection(Edm.EntityType)
对虚拟集合 $all 的请求(参见 [OData‐URL])的响应使用内置的抽象实体类型。这样响应中的每个单个实体都有其标识实体集或单例的独立上下文 URL。
10.20 $crossjoin 响应
上下文 URL 模板:
{context-url}#Collection(Edm.ComplexType)
对虚拟集合 $crossjoin(...) 的请求(参见 [OData‐URL])的响应使用内置的抽象复杂类型。这些响应中的单个实例不具有上下文 URL。
11 数据服务请求
本章描述了 GET、POST、PATCH、PUT 和 DELETE 这些 HTTP 请求谓词对 OData 资源的语义。
GET 请求
- 11.1 元数据请求及其子章节
- 11.2 请求数据及其子章节
- 11.3 请求更改及其子章节
- 11.5.4 函数及其子章节
POST 请求
- 11.4.2 创建实体及其子章节
- 11.4.7.1 创建媒体实体
- 11.4.11 按位置插入
- 11.5.5 操作及其子章节
- 11.7 批处理请求及其子章节
PATCH 和 PUT 请求
- 11.4.3 更新实体及其子章节
- 11.4.4 置入实体
- 11.4.6 修改实体之间的关系及其子章节
- 11.4.7.2 更新媒体实体流
- 11.4.8.1 更新流值
- 11.4.9.1 更新原始属性
- 11.4.9.3 更新复杂属性
- 11.4.9.4 更新集合属性
- 11.4.10 管理有序集合的成员
- 11.4.12 更新实体集合
- 11.4.13 更新集合成员
DELETE 请求
- 11.4.5 删除实体
- 11.4.7.3 删除媒体实体
- 11.4.9.2 将值设置为 null
- 11.4.14 删除集合成员
11.1 元数据请求
OData 服务是一种自描述服务,它公开定义实体集、单例、关系、实体类型和操作的元数据。
11.1.1 服务文档请求
服务文档使简单的超媒体驱动的客户端能够枚举和探索数据服务提供的资源。
OData 服务必须支持从服务的根 URL(服务 root)返回服务文档。
服务文档的格式取决于所选的格式。
11.1.2 元数据文档请求
OData 元数据文档是对描述由 OData 服务公开的数据和操作的数据模型的表示。
[OData-CSDLJSON] 描述了 OData 元数据文档的 JSON 表示形式,并提供了一个 JSON schema 来验证其内容。OData 元数据文档的 JSON 表示形式的媒体类型是 application/json。
[OData-CSDLXML] 描述了 OData 元数据文档的 XML 表示形式,并提供了一个 XML schema 来验证其内容。OData 元数据文档的 XML 表示形式的媒体类型是 application/xml。
OData 服务可以公开描述服务公开的数据模型的元数据文档。元数据文档 URL 必须是服务的根 URL 加上 $metadata。要检索此文档,客户端向元数据文档 URL 发出 GET 请求。
如果元数据请求没有指定首选格式(通过 Accept 头或 $format),则必须返回 XML 表示形式。
11.2 请求数据
OData 服务支持通过 HTTP GET 请求数据。
URL 的路径指定请求的目标(例如,实体集合、实体、导航属性、结构属性或操作)。额外的查询操作符,如筛选、排序、分页和投影操作是通过查询选项指定的。
本节描述了 OData 定义的数据请求类型。有关构建请求语法的完整详细信息,请参阅 [OData‐URL]。
OData 服务是基于超媒体的服务,它会返回 URL 给客户端。如果客户端后续请求已公布的资源,而 URL 已过期,那么服务应响应 410 Gone。如果不可行,服务必须响应 404 Not Found。
返回的数据格式取决于请求和客户端指定的格式,客户端可以在 Accept 头或使用$format查询选项中指定。如果客户端既没有指定Accept头也没有指定format 查询选项,则允许服务以任何格式返回响应。
11.2.1 系统查询选项
OData 定义了许多允许细化请求的系统查询选项。系统查询选项以美元 ( ) 字符为前缀,这在 OData 4.01 中是可选的。4.01 服务必须支持带或不带
前缀指定的不区分大小写的系统查询选项名称。
想要使用 4.0 服务的客户端必须使用小写名称并指定$前缀。
想要使用 4.0 服务的客户端必须使用小写名称和指定 $ 前缀。
请求的结果必须像系统查询选项按以下顺序评估的结果一样。
- $schemaversion 必须首先评估,因为它可能会影响任何进一步的处理。
应用任何服务器端分页之前:
- $apply – 定义在 [OData-Aggregation] 中
- $compute
- $search
- $filter
- $count
- $orderby
- $skip
- $top
应用任何服务器端分页之后:
- $expand
- $select
- $format
11.2.2 请求单个实体
要检索单个实体,客户端对标识实体的 URL(例如读取 URL)发出 GET 请求。
可以从包含该实例的响应有效负载中获得读取 URL,例如 [OData-JSON] 有效负载中的 readLink 或 editLink。 此外,服务可能支持使用实体的键值构造读取 URL 的约定,如 [OData‐URL] 中所述。
可以通过 ������或select或expand 系统查询选项指定要返回的结构属性或导航属性集。
客户端必须准备好在实体或复杂类型实例中接收元数据中未advertised的附加属性,甚至对于未标记为开放类型的类型也是如此。
如果不可用的属性(例如因权限原因)不会返回。 在这种情况下,[OData-VocCore] 中定义的 Core.Permissions 注释必须为属性返回,值为 None。
如果指定的请求 URL 不存在实体,服务会以 404 Not Found 响应。
11.2.3 使用 $value 请求媒体实体的媒体流
媒体实体是代表出席流的实体,例如照片。
如果出席流是主要关注的焦点,并且媒体实体仅是附加到流上的结构化附加信息,则使用媒体实体。 如果实体的结构化数据是主要关注的焦点,并且流数据仅是附加到结构化数据的附加信息,则使用具有一个或多个流属性的正常实体。
要寻址媒体实体表示的媒体流,客户端将 /$value 附加到媒体实体 URL 的资源路径。 服务可以从此规范 URL 重定向到媒体流的源 URL。
如果附加 /$value 到一个非媒体实体,会返回 400 Bad Request。
如果尝试从引用值为 null 的媒体实体的单值导航属性中检索媒体流,会返回 404 Not Found。
11.2.4 请求单个属性
要检索单个属性,客户端向属性 URL 发出 GET 请求。 属性 URL 是实体读取 URL 与属性名称的拼接。
对于复杂类型的属性,路径可以用复杂类型的单个属性名称进一步扩展。
详情见 [OData‐URL]。
如果属性为单值并且值为 null,服务会以 204 No Content 响应。
如果属性不可用(例如因权限原因),服务会以 404 Not Found 响应。
示例 31:
GET http://host/service/Products(1)/Name
11.2.4.1 使用 $value 请求属性的原始值
要检索原始类型属性的原始值,客户端向属性值 URL 发送 GET 请求。 参见 [OData‐URL] 文档获取详细信息。
响应的 Content-Type 使用 Accept 标头和 $format 系统查询选项确定。
如果存在,Edm.Binary 的默认格式是此属性的 Core.MediaType 注释指定的格式(参见 [OData-VocCore])。 如果未注释,客户端无法预测格式。
Edm.Geo 类型的默认格式是文本/普通,使用 WKT(well-known text)格式,参见 [OData-ABNF] 中的 fullCollectionLiteral、fullLineStringLiteral、fullMultiPointLiteral、fullMultiLineStringLiteral、fullMultiPolygonLiteral、fullPointLiteral 和 fullPolygonLiteral 规则。
除 Edm.Binary 和 Edm.Geo 类型之外的单个基元值的默认格式是文本/普通。 Edm.String 类型属性的响应可以使用 charset 格式参数指定用于表示字符串值的字符集。 其他基元类型遵循 [OData-ABNF] 中的 booleanValue、byteValue、dateValue、dateTimeOffsetValue、decimalValue、doubleValue、durationValue、enumValue、guidValue、int16Value、int32Value、int64Value、sbyteValue、singleValue 和 timeOfDayValue 规则。
对于 null 值的属性,$value 请求会以 204 No Content 响应。
如果属性不可用(例如因权限原因),服务会以 404 Not Found 响应。
示例 32:
GET http://host/service/Products(1)/Name/$value
11.2.5 指定要返回的属性
select和
expand 系统查询选项使客户端能够指定要在响应中包含的结构属性和导航属性集。 服务可能包括 和select和
expand 中未指定的附加属性,包括元数据文档中未定义的属性。
11.2.5.1 系统查询选项$select
$select 系统查询选项要求服务端只返回客户明确请求的属性,动态属性,操作和函数。服务端会返回指定的内容(如果可用的话),以及可用的扩展导航或流属性,并且可能会返回额外的信息。
$select 查询选项的值是一个逗号分隔的属性列表,限定的操作名,限定的函数名,星号操作符(*)或带有模式命名空间或别名的星号操作符,以指定在该模式中定义的所有操作。只有在服务的元数据文档中定义的别名才能在 URL 中使用。
示例33:只请求匹配的产品的评级和发布日期
GET http://host/service/Products?$select=Rating,ReleaseDate
也可以使用星号操作符请求所有结构属性,包括任何动态属性。星号操作符不应引入否则未请求的导航属性、操作或函数。
实施例34:
获取 http://host/service/Products?$select=*
可以通过在expand中包含
select查询选项来指定相关实体的属性。
实施例35:
GET http://host/service/Products?$expand=类别($select=名称)
除了任何扩展的导航或流属性之外,还表示select中指定的属性。如果在
select 中指定了导航属性,则相应的导航链接将在响应中表示。如果导航属性也出现在$expand 查询选项中,则它另外表示为内联内容。
示例 36:对于每个类别,返回 CategoryName 和 Products 导航链接
GET http://host/service/Categories?$select=CategoryName,产品
还可以请求每个返回实体可用的所有操作或功能。
实施例37:
获取 http://host/service/Products?$select=DemoService.*
查询选项可以通过以分号分隔的查询选项列表(用括号括起来)追加到属性上,应用于所选属性。允许的系统查询选项是select和compute用于复杂属性,以及 filter、search、count、orderby 和 skip 和 top 用于集合值属性。一个属性在一个请求中不能有多个地方指定选择选项,也不能同时指定选择和展开选项。
如果未指定 select 查询选项,服务将返回完整的属性集或默认属性集。默认属性集必须包括所有关键属性。
如果服务由于客户端指定了选择或者服务在没有选择的情况下返回属性子集而返回不完整的属性集,上下文URL必须反映所选属性集和投影的扩展导航属性。
11.2.5.2 系统查询选项$expand
$expand 系统查询选项表示必须以内联方式表示的相关实体和流值。服务必须返回指定的内容,并且可以选择返回其他信息。
$expand 查询选项的值是一个导航属性名称、流属性名称或表示媒体实体的流内容的 value 的逗号分隔列表。
对于导航属性,导航属性名称后面可选地跟着一个/路径段或一个 /ref 路径段或一个/count 路径段,以及可选的一组用括号括起来的展开选项(用于筛选、排序、选择、分页或展开相关实体)。
完整的请求语法详见[OData‐URL]。
示例38:对于 Customers 实体集中的每个客户实体,所有相关 Orders 的值将以内联方式表示
GET http://host/service.svc/Customers?$expand=Orders
示例39:对于 Customers 实体集中的每个客户实体,相关 Orders 的引用将内联表示
GET http://host/service.svc/Customers?$expand=Orders/$ref
示例40:对于 Customers 实体集中的每个客户实体,表示客户照片的媒体流将内联表示
GET http://host/service.svc/Customers?$expand=Photo
11.2.5.2.1 展开选项
通过应用展开选项可以进一步细化展开实体集,表达为以分号分隔的系统查询选项列表,用括号括起来,参见 [OData‐URL]。
允许的系统查询选项是 filter、
select、orderby、
skip、top、
count、search、
expand 和 compute和
levels。
示例 41:对于 Customers 实体集中的每个客户实体,金额大于 100 的相关 Orders 的值将内联表示
GET http://host/service.svc/Customers?$expand=Orders($filter=Amount gt 100)
示例42:对于 Orders 实体集中的每个订单,以下内容将内联表示:
- 通过 URL 资源路径部分标识的与 Orders 相关的 Items 以及与每个订单项相关的 products。
- 与每个订单相关的 Customer。
GET http://host/service.svc/Orders?$expand=Items($expand=Product),Customer
示例 43: 对于 Customers 实体集中的每个客户实体,如果该实体类型为 VipCustomer 或其子类型,则相关的所有 InHouseStaff 的值将内联表示。对于不是 VipCustomer 或其任何子类型的实体,可以返回没有 InHouseStaff 内联表示的实体(服务始终可以发送比请求的更多)。
GET http://host/service.svc/Customers?$expand=SampleModel.VipCustomer/InHouseStaff
11.2.5.2.1.1 展开选项 $levels
levels扩展选项 可用于指定层次结构的递归级别数,其中相关实体类型与源实体类型相同或可以转换为源实体类型。值为 1 的
levels选项指定不带递归的单次扩展。相同的扩展选项适用于层次结构的每个级别。
除了数值之外,服务还可以支持符号值 max 。在这种情况下,它们必须通过在循环依赖中的某处注入实体引用来解决循环依赖。
使用 $levels=max 的客户端必须准备好处理实体引用,否则会发生循环引用。
4.01 支持max 的服务应该以不区分大小写的方式进行。想要使用 4.0 服务的客户端必须使用小写。
示例 44:返回员工实体集中的每个员工,并且对于作为经理的每个员工,返回所有直接下属,递归到四个级别
获取 http://host/service/Employees?$expand=Model.Manager/DirectReports($levels=4)
11.2.5.3 系统查询选项 $compute
compute 系统查询选项允许客户端定义可在
select 中使用或在或 filter 或
orderby 表达式中使用的计算属性。
计算属性应该作为动态属性包含在结果中,并且如果使用计算属性名称或星号 ( * )指定 $select ,则必须包含计算属性。
示例45:(仅为便于阅读而换行)
GET http://host/service/Customers?
filter=Orders/any(o:o/TotalPrice gt 100) &expand=Orders($compute=Price mult Qty as TotalPrice
;$select=Name,Price,Qty,TotalPrice)
11.2.6 查询集合
OData 服务支持查询实体、复杂类型实例和原始值的集合。
目标集合通过 URL 指定,并且过滤、排序、分页和投影等查询操作被指定为系统查询选项,可选地以美元 ( ) 字符作为前缀。4.01 服务必须支持带或不带
前缀指定的不区分大小写的系统查询选项名称。想要使用 4.0 服务的客户端必须使用小写名称并指定$前缀。
不得为任何资源多次指定相同的系统查询选项。
OData 服务可以支持部分或全部定义的系统查询选项。如果数据服务不支持系统查询选项,则它必须使包含不支持选项的任何请求失败,并且应该返回 501 Not Implemented。
11.2.6.1 $filter 系统查询选项
$filter 系统查询选项限制返回的项集。
示例 46:返回价格小于 $10.00 的所有产品
GET http://host/service/Products?$filter=Price lt 10.00
count片段可在
filter 表达式中使用,根据相关实体或集合值属性内的项的确切计数来限制返回的项。
示例 47:返回少于 10 种产品的所有类别
GET http://host/service/Categories?$filter=Products/$count lt 10
$filter 选项的值是一个布尔表达式,如[OData-ABNF]中定义。
11.2.6.1.1 内置过滤器操作
OData 支持一组内置筛选器操作,如本节中所述。
4.01 服务必须支持不区分大小写的操作名称。想要使用 4.0 服务的客户端必须使用小写操作名称。
构建请求时使用的完整语法,请参阅 [OData‐URL]。
操作符 | 描述 | 示例 |
---|---|---|
比较操作符 | ||
eq | 等于 | Address/City eq 'Redmond' |
ne | 不等于 | Address/City ne 'London' |
gt | 大于 | Price gt 20 |
ge | 大于等于 | Price ge 10 |
lt | 小于 | Price lt 20 |
le | 小于等于 | Price le 100 |
has | 具有标志 | Style has Sales.Color'Yellow' |
in | 是成员 | Address/City in ('Redmond', 'London') |
逻辑操作符 | ||
and | 逻辑与 | Price le 200 and Price gt 3.5 |
or | 逻辑或 | Price le 3.5 or Price gt 200 |
not | 逻辑否定 | not endswith(Description,'milk') |
算术操作符 | ||
add | 加法 | Price add 5 gt 10 |
sub | 减法 | Price sub 5 gt 10 |
mul | 乘法 | Price mul 2 gt 2000 |
div | 除法 | Price div 2 gt 4 |
divby | 十进制除法 | Price divby 2 gt 3.5 |
mod | 模数 | Price mod 2 eq 0 |
分组操作符 | ||
( ) | 优先级分组 | (Price sub 5) gt 10 |
11.2.6.1.2 内置查询函数
OData 支持在 $filter 操作中使用的一组内置函数。下表列出了可用的函数。
4.01 服务必须支持不区分大小写的内置函数名。想要使用 4.0 服务的客户端必须使用小写名。
构建请求时使用的完整语法,请参阅 [OData‐URL]。
OData 没有定义 ISNULL 或 COALESCE 操作符。而是有一个 null 字面量可以用于比较。
函数 | 示例 |
---|---|
字符串和集合函数 | |
concat | concat(concat(City,', '), Country) eq 'Berlin, Germany' |
contains | contains(CompanyName,'freds') |
endswith | endswith(CompanyName,'Futterkiste') |
indexof | indexof(CompanyName,'lfreds') eq 1 |
length | length(CompanyName) eq 19 |
startswith | startswith(CompanyName,’Alfr’) |
substring | substring(CompanyName,1) eq 'lfreds Futterkiste' |
集合函数 | |
hassubset | hassubset([4,1,3],[3,1]) |
hassubsequence | hassubsequence([4,1,3,1],[1,1]) |
字符串函数 | |
matchesPattern | matchesPattern(CompanyName,'%5EA.*e') |
tolower | tolower(CompanyName) eq 'alfreds futterkiste' |
toupper | toupper(CompanyName) eq 'ALFREDS FUTTERKISTE' |
trim | trim(CompanyName) eq 'Alfreds Futterkiste' |
日期时间函数 | |
day | day(StartTime) eq 8 |
date | date(StartTime) ne date(EndTime) |
fractionalseconds | second(StartTime) eq 0 |
hour | hour(StartTime) eq 1 |
maxdatetime | EndTime eq maxdatetime() |
mindatetime | StartTime eq mindatetime() |
minute | minute(StartTime) eq 0 |
month | month(BirthDate) eq 12 |
now | StartTime ge now() |
second | second(StartTime) eq 0 |
time | time(StartTime) le StartOfDay |
totaloffsetminutes | totaloffsetminutes(StartTime) eq 60 |
totalseconds | totalseconds(duration'PT1M') eq 60 |
year | year(BirthDate) eq 0 |
算术函数 | |
ceiling | ceiling(Freight) eq 33 |
floor | floor(Freight) eq 32 |
round | round(Freight) eq 32 |
类型函数 | |
cast | cast(ShipCountry,Edm.String) |
isof | isof(NorthwindModel.Order) |
isof | isof(ShipCountry,Edm.String) |
地理函数 | |
geo.distance | geo.distance(CurrentPosition,TargetPosition) |
geo.intersects | geo.intersects(Position,TargetArea) |
geo.length | geo.length(DirectRoute) |
条件函数 | |
case | case(X gt 0:1,X lt 0:-1,true:0) |
11.2.6.1.3 参数别名
参数别名可以代替实体键、函数参数或 compute、
filter 或 $orderby表达式中的字面值。参数别名是以@符号开头的名称。
实际参数值在请求 URL 的查询部分中指定为查询选项。查询选项名称是参数别名的名称,查询选项值是指定参数别名要使用的值。
示例 48:返回 Region 属性与字符串参数值“WA”匹配的所有员工
获取http://host/service.svc/Employees?$filter=Region eq @p1&@p1='WA'
参数别名允许在请求中多次使用相同的值,并且可用于引用原始值、结构化值或集合值。
如果在请求 URL 的查询部分中未给参数别名指定值,则该值必须假定为 null。参数别名可以在请求 URL 中的多个位置使用,但不得多次指定其值。
/$filter路径段中使用的参数别名值 始终作为表达式传递(因为这是参数的预期类型)。
所有其他参数别名值都在由路径段标识的资源上下文中求值,在路径段中分配这些值并将其作为值传递到表达式中。参数别名值分配可以嵌套在expand和
select中,在这种情况下,它们是相对于expand或
select的资源上下文进行评估的。
示例 49:返回所有员工,展开他们的经理,并展开与经理同名的所有直接下属,使用$this 的参数别名将经理传递到展开的直接下属的过滤器中
获取 http://host/service.svc/Employees?$expand=Manager(@m=$this;$expand=DirectReports($filter=@m/FirstName eq FirstName))
11.2.6.2 系统查询选项 $orderby
$ orderby 系统查询选项指定从服务返回项目的顺序。
$orderby 系统查询选项的值包含一个以逗号分隔的表达式列表,其原始结果值用于对项目进行排序。这种表达式的一个特殊情况是终止于原始属性的属性路径。需要使用限定实体类型名称进行类型转换,以便按派生类型上定义的属性进行排序。只有在服务的元数据文档中定义的别名才能在 URL 中使用。
该表达式可以包含后缀 asc( 表示升序)或 desc(表示降序),与属性名称之间用一个或多个空格分隔。如果未指定asc 或 desc,则服务必须按指定属性升序排序。4.01 服务必须支持 asc 和 desc 的不区分大小写的值。想要使用 4.0 服务的客户端必须使用小写值。
按升序排序时,空值位于非空值之前;按降序排序时,空值位于非空值之后。
项目按第一个表达式的结果值排序,然后第一个表达式具有相同值的项目按第二个表达式的结果值排序,依此类推。
布尔值 false 按升序排列在值 true 之前。
服务应该根据响应的内容语言对语言相关的字符串进行排序,并且应该使用术语Core.IsLanguageDependent来注释与语言相关的顺序的字符串属性,请参阅 [OData-VocCore] 。
Edm.Stream类型或任何Geo 类型的值无法排序。
示例 50:返回按发布日期升序排序的所有产品,然后按评级降序排序
GET http://host/service/Products?$orderby=ReleaseDate asc,评级 desc
可以通过在expand子句中指定
orderby来对相关实体进行排序。
示例 51:返回所有类别及其根据发布日期和评级降序排序的产品
GET http://host/service/Categories?
expand=产品(
orderby=发布日期 asc, 评级 desc)
count 可以在
orderby 表达式中使用,以根据集合值属性中相关实体或项目的确切计数对返回的项目进行排序。
示例 52:返回按每个类别内的产品数量排序的所有类别
获取 http://host/service/Categories?$orderby=Products/$count
11.2.6.3 系统查询选项$top
$top系统查询选项 指定一个非负整数 n,用于限制从集合返回的项目数。该服务返回最多但不大于指定值 n 的可用项目数。
示例 53:仅返回 Products 实体集的前五个产品
获取 http://host/service/Products?$top=5
如果没有通过 $orderby 查询选项施加唯一排序,则服务必须在包含top的请求之间施加稳定排序。
11.2.6.4 系统查询选项$skip
$skip 系统查询选项 指定一个非负整数 n,该整数从结果中排除查询集合的前 n 项。该服务返回从位置 n+1 开始的项目。
示例 54:返回从Products实体集的第 6 个产品开始的产品
获取 http://host/service/Products?$skip=5
当一起使用 top 和
skip 时,必须在 skip 必须在
top 之前应用,而不考虑它们在请求中的出现顺序。
示例 55:返回 Products 实体集的第三个到第七个产品
获取 http://host/service/Products?$top=5&$skip=2
如果没有通过 $orderby 查询选项施加唯一排序,则服务必须在包含 skip 的请求之间施加稳定排序。
11.2.6.5 系统查询选项$count]
值为 true的 $count 系统查询选项指定与结果一起返回集合中与请求匹配的项目总数。
示例 56:返回集合中的产品总数以及结果
获取 http://host/service/Products?$count=true
可以通过在 expand 子句中指定
count查 询选项来请求相关实体的计数 。
实施例57:
获取 http://host/service/Categories?$expand=Products($count=true)
值为 false (或未指定)的$count查询选项暗示服务不应返回计数。
如果指定 true 或 false 以外的值,则服务将返回 HTTP 状态代码 400 Bad Request 。
count 系统查询选项会忽略任何 top 或
skip 或 expand 查询选项,并返回所有页面的结果总数,其中只包括匹配任何指定的和 $filter 和 search 的结果。客户端应该意识到内联返回的计数可能与实际返回的项目数量不完全匹配,这是由于在计算最后一个计数和枚举最后一个值之间的延迟造成的,或者由于服务上的不精确计算。
计数在响应正文中的编码方式取决于所选的格式。
11.2.6.6 系统查询选项$search
系统查询选项 $search 限制结果仅包含与指定搜索表达式匹配的项。匹配的定义取决于实现方式。
例子 58: 返回所有匹配搜索词 "bike" 的产品
GET http://host/service/Products?$search=bike
搜索表达式可以包含用双引号括起来的短语。
例子 59: 返回所有匹配短语 "mountain bike" 的产品
GET [http://host/service/Products?search="mountain](http://host/service/Products?
search=%22mountain) bike"
大写关键字 NOT 限制实体集合仅包含不匹配指定词的实体。
例子 60: 返回所有不匹配 "clothing" 的产品
GET http://host/service/Products?$search=NOT clothing
搜索表达式中的多个项由空格(隐式 AND)或大写关键字 AND 分隔,表示所有这些项都必须匹配。
例子 61: 返回同时匹配 "mountain" 和 "bike" 的产品
GET http://host/service/Products?$search=mountain AND bike
大写关键字 OR 用于返回既满足前面的表达式,又满足后面的表达式的实体。
例子 62: 返回同时匹配 "mountain" 或 "bike" 的产品
GET http://host/service/Products?$search=mountain OR bike
搜索表达式中的括号可用于分组多个表达式。
例子 63: 返回既满足 "mountain" 或 "bike" 的产品,又不满足 "clothing" 的产品
GET http://host/service/Products?$search=(mountain OR bike) AND NOT clothing
搜索表达式中的操作必须按照以下顺序计算:分组运算符,NOT 运算符,AND 运算符,OR 运算符
如果在同一请求中同时指定了 search 和
filter,只有同时满足两个条件的项将被返回。
$search 选项的值是一个搜索表达式,其定义在 [OData-ABNF] 中。
11.2.6.7 服务器驱动的分页
仅返回部分满足请求 URL 的项的响应必须包含一个链接,用于检索下一部分满足的项集合。这个链接称为下一个链接,其表示形式依赖于特定的格式。最后一部分满足的项集合不得包含下一个链接。
客户端可以通过 maxpagesize 参数请求最大页面大小。服务可能应用该请求的页面大小,或者在没有该参数或与其不符的情况下实现不同的页面大小。
OData 客户端必须将下一个链接的 URL 视为不透明,并且不得在下一个链接的 URL 上附加系统查询选项。服务可能不允许在使用下一个链接请求的后续页面上更改格式。因此,客户端应该在后续页面请求时使用兼容的 Accept 头请求相同的格式。OData 服务可以在构建下一个链接时使用保留的系统查询选项 $skiptoken。其内容是不透明、特定于服务的,并且必须遵循 URL 查询部分的规则。
构建请求时,OData 客户端不得使用系统查询选项 $skiptoken。
11.2.6.8 请求有序集合的个体成员
使用一个包含从零开始的序号段添加到集合的 URL 上,可以访问被标记为 Ordered 的原始和复杂类型的集合的个体成员。负数序号从集合的末尾开始计数,-1 代表集合中的最后一项。
实体可以通过其标准 URL 稳定地进行定址,不可使用序号索引。
例子 64:主要供应商的地址列表中的第一个地址
GET http://host/service/Suppliers(MainSupplier)/Addresses/0
11.2.7 请求相关实体
为了根据特定关系请求相关实体,客户端向源实体的请求 URL 发出 GET 请求,后跟斜杠和表示关系的导航属性的名称。
如果导航属性不存在于请求 URL 指示的实体上,服务将返回 404 Not Found。
如果关系终止于集合,响应必须是包含相关实体集合的特定格式的表示。如果没有相关的实体,响应是表示空集合的特定格式的表示。
如果关系终止于单个实体,响应必须是表示相关单个实体的特定格式的表示。如果没有相关实体,服务返回 204 No Content。
例子 65:返回具有 ID=1 的产品的供应商
GET http://host/service/Products(1)/Supplier
11.2.8 请求实体引用
为了请求实体引用而不是实际实体,客户端在资源路径后附加 /$ref 发出 GET 请求。
如果资源路径没有标识实体或实体集合,服务返回 404 Not Found。
如果资源路径标识集合,响应必须是引用相关实体的特定格式的集合表示。如果没有相关实体,响应是特定格式的表示空集合。响应可能包含一个 ETag 标头,表示引用集合的值是否更改,即引用添加或删除。
如果资源路径标识单个现有实体,响应必须是实体引用的特定格式的表示。响应可能包含表示引用实体标识的 ETag 标头。如果资源路径终止于单值导航路径,当关系变化并指向不同的 OData 实体时,ETag 值会发生变化。如果资源路径是单个实体的规范路径,则返回的 ETag 永远不会更改。
如果资源路径终止在单个实体上,且不存在这样的实体,服务会返回 204 No Content 或 404 Not Found。
例子 66:具有对与 ID=0 的产品相关的每个订单的实体引用的集合
GET http://host/service/Products(0)/Orders/$ref
11.2.9 解析实体 ID
为了将实体 ID(例如在实体引用中获得)解析为已识别实体的表示,客户端向 位于相对于服务根的URL entity 处的
entity 资源发出 GET 请求。实体 ID 必须使用系统查询选项 $id 指定。
示例 67:返回给定实体 ID 的实体表示
获取 http://host/service/$entity?$id=http://host/service/Products(0)
在 $entity 资源之后的类型段将资源转换为指定的类型。如果所标识的实体不是指定类型或派生自指定类型,则服务返回 404 Not Found。
在将类型转换段应用于指定类型后,可以在 GET 请求的 entity 资源中指定系统查询选项 select 和
expand。
示例 68:返回给定实体 ID 的实体表示并指定要返回的属性
GET http://host/service/$entity/Model.Customer
?$id=http://host/service/Customers('ALFKI')
&$select=CompanyName,ContactName
&$expand=Orders
11.2.10 请求集合中的项目数量
要仅请求实体集合的项目数或集合值属性的项目数,客户端发出GET请求,并将/$count 附加到集合的资源路径。
成功时,响应正文必须包含应用任何或 filter 或
search 系统查询选项后匹配请求的项目数量,以文本/纯文本媒体类型格式化的简单原始整数值。客户端不应在路径后缀中与系统查询选项 $count 中与系统查询选项 top、skip、orderby 和 expand 和 format 结合使用。此类请求的结果未定义。
示例 69:返回 Products 实体集中的产品数量
GET http://host/service/Products/$count
在 4.01 版服务中,/count 段可与 /filter 路径段结合使用来计算筛选集合中的项目数量。
示例 70:返回价格低于 $10.00 的产品数量
GET http://host/service/Products/$filter(@foo)/$count?@foo=Price lt 10.00
为了向后兼容,/count 后缀可与 filter 系统查询选项结合使用。
示例 71:返回价格低于 $10.00 的产品数量
GET http://host/service/Products/$count?$filter=Price lt 10.00
不能在同时有 /count 路径段和/filter 路径段的情况下使用 $filter 系统查询选项。
/count 后缀也可在系统查询选项内的路径表达式中使用,例如count后缀也可在系统查询选项内的路径表达式中使用,例如filter。
示例 72:返回拥有超过五个兴趣的所有客户
GET http://host/service/Customers?$filter=Interests/$count gt 5
示例 73:返回售价高于 $5.00 的一个以上产品的所有类别
GET http://host/service/Categories?
/filter= Products/filter(Price gt 5.0)/$count gt 1
11.2.11 系统查询选项 $format
$format系统查询选项指定响应的媒体类型。
$format查询选项(如果存在于请求中)必须优先于Accept请求标头中指定的值 。
$format系统查询选项的值是有效的互联网媒体类型,可以选择包含参数。
此外,可以使用特定于格式的缩写,例如 application/json的json,请参阅 [OData-JSON] ,但格式参数不得附加到格式缩写。
示例74:请求
获取 http://host/service/Orders?$format=application/json;metadata=full
相当于 使用相同媒体类型的带有Accept标头的请求;它请求使用 JSON 媒体类型表示的订单实体集,包括完整元数据,如 [OData-JSON] 中定义。
示例75:请求
获取 http://host/service/Orders?$format=json
相当于Accept 标头设置为application/json 的请求;它请求使用具有最少元数据的 JSON 媒体类型表示的 Order 实体集,如 [OData-JSON] 中所定义。
在元数据文档请求中,保留了 application/xml 和 application/json 两个值及其子类型和参数化变体,以及 xml 和 json 这两个格式特定的缩写,专为此规范使用。
11.2.12 系统查询选项 $schemaversion
schemaversion 系统查询选项可包含在任何请求中。对于元数据文档请求,schemaversion 系统查询选项的值表示特定模式版本。对于所有其他请求类型,该值指定请求所应用的模式的版本。schemaversion 系统查询选项的语法在 [OData-ABNF] 中定义。
$schemaversion 系统查询选项的值必须是先前请求的元数据文档返回的 Core.SchemaVersion 注解(在 [OData-VocCore] 中定义)的模式版本,或者是 * 以指定当前版本的元数据。
如果指定,服务必须根据指定版本的元数据处理请求。
客户端可以通过使用 $schemaversion 系统查询选项值为∗进行元数据文档请求,从而检索元数据的当前版本,并应在后续请求的schemaversion 系统查询选项中包含返回的 Core.SchemaVersion 注解中的值。
如果在元数据文档的请求中未指定schemaversion系统查询选项,则服务必须返回一个不随时间发生重大更改的元数据版本,并且必须处理省略
schemaversion 系统查询选项的所有其他 请求与“无版本化”模式兼容。有关重大更改的更多信息,请参阅模型版本控制。
如果在批处理中的单个请求上指定 schemaversion 系统查询选项,则它指定要应用于该单个请求的架构版本。批处理中不包含
schemaversion 系统查询选项的各个请求将继承整个批处理请求的架构版本。
- 如果指定了 $schemaversion 系统查询选项,但模式的版本不存在,则以响应代码 404 Not Found 回答请求。响应正文应提供额外信息。
11.3 请求变更
服务通过在实体集上注释 Capabilities.ChangeTracking 来广告其变更跟踪功能,该术语在 [OData-VocCap] 中定义。
检索一个或多个实体的任何 GET 请求都可以允许变更跟踪。
客户端通过在请求上指定 track-changes 首选项来请求服务跟踪对结果的更改。如果对该请求支持,服务将在响应中包含一个 Preference-Applied 标头,其中包含 track-changes 首选项,并在单个实体的结果和实体集合的最后一页结果中,以替代下一页链接的方式,包含一个增量链接。
11.3.1 增量链接
增量链接是不透明的、由服务生成的链接,客户端使用它来检索结果的后续更改。
增量链接基于定义的查询,该查询描述了正在跟踪更改的结果集,例如生成包含增量链接的结果的请求。增量链接编码了正在跟踪更改的实体集合,以及用于跟踪更改的起始点。OData 服务可以在构建增量链接时使用保留的系统查询选项 $deltatoken。其内容是不透明的、特定于服务的,并且必须遵循 URL 查询部分的规则。
如果定义的查询包含 $schemaversion 系统查询选项,则响应必须根据该模式版本来表示。
如果定义的查询包含 ������或filter或search,则响应必须仅包括与指定条件匹配的实体的更改。对于已添加或更改并且现在与指定的条件匹配的实体,必须返回已添加的实体;对于已更改以不再匹配 ������或filter或search 条件的实体,必须返回已删除的实体。
增量链接不得编码任何客户端的 top 或 skip 值,并且不应该编码对内联计数的请求。
如果定义的查询包括扩展的关系,则增量链接必须返回扩展实体的更改、添加或删除,以及返回扩展实体或表示当前成员身份的嵌套集合的添加或删除链接。如果定义的查询包括扩展的引用,则增量链接必须返回对扩展引用集合中成员身份的更改。
在定义的查询的select 列表中指定的导航属性不用于定义正在跟踪的项目的范围或内容。客户端可以在select列表中指定的导航属性不用于定义正在跟踪的项目的范围或内容。客户端可以在expand 中指定 /
ref,以便指定对相关实体集的兴趣,而不关注这些相关实体的内容的变化。
如果一个扩展实体变得孤立,因为在定义的查询中指定的所有路径到实体都被断开(例如由于关联更改和/或父实体的更改或删除) ,那么服务必须返回适当的通知,以便客户端确定该实体已被孤立(即更改的关联关系和移除的父实体)。客户端不应假设会收到有关此类孤立实体的其他通知。
如果任何结构属性发生更改,则实体被视为已更改。对相关实体和流的更改不被视为包含流或导航属性的实体的更改。
如果定义的查询包含投影,则生成的增量链接应逻辑上包含相同的投影,以便增量查询仅包括投影中指定的字段。服务可以使用投影来将返回的实体限制为在所选字段内发生更改的实体集,但客户端必须准备接收返回的实体,无论更改的字段是否在投影中指定。
11.3.2 使用 Delta 链接
客户端通过在增量链接上调用 GET 方法来请求更改。客户端不得尝试在增量链接上附加系统查询选项。可以使用 Accept 标头来指定所需的响应格式。
在查询增量链接时,客户端应该指定与定义的查询中指定的 Accept-Language 标头相同的值。如果指定了不同的 Accept-Language,则服务可以返回 406 Not Acceptable。如果服务支持 Accept-Language 标头,它可以只返回在指定语言中可见的更改,或者可以包括没有在请求的语言中可见的更改的记录。
可以将 /$count 段追加到增量链接的路径中,以仅获取可用的更改数。计数包括所有添加、更改或删除的实体,以及添加或删除的链接。
对增量链接的请求结果可能跨多个页面,但服务必须对所有页面进行排序,以确保应用于响应的顺序时一致性。
服务应该只返回已更改的实体,但可以返回与定义的查询匹配的其他实体,客户端可能无法看到这些实体的更改。
为了继续跟踪当前集之外的更改,客户端在对增量链接的初始请求上指定 track-changes,但不需要在后续页面上重复指定。新的增量链接出现在上一个增量链接的最后一组更改的末尾,以替代下一页链接,并且必须返回自上一个增量链接的最后一个更改之后的所有更改。
如果没有发生更改,响应是一个包含用于后续更改的增量链接的空集合。如果请求,这个增量链接可能与生成空的更改集合的增量链接相同。
如果增量链接不再有效,服务将返回 410 Gone,并且应该在响应的 Location 标头中包含重新获取整个集合的 URL。
11.3.3 Delta 有效负载
增量有效负载表示对已知状态的更改。增量有效负载包括添加的实体、更改的实体和删除的实体,以及添加和删除的关系的表示。
可以使用增量链接从服务请求增量负载,或者将其提供为服务的更新。
11.4 数据修改
可修改的 OData 服务支持创建、更新和删除操作,适用于部分或全部公开的实体。此外,由服务支持的操作可能会影响系统的状态。
成功完成的数据修改请求不得违反数据的完整性。
客户端可以通过指定返回 Prefer 头来请求在创建、更新或删除请求或调用操作时返回的内容。
11.4.1 常见数据修改语义
数据修改请求 共享以下语义。
11.4.1.1 使用 ETag 避免更新冲突
每个实体都有自己的 ETag 值,当该实体的结构属性或链接发生更改时,ETag 值必须更改。此外,修改、添加或删除包含实体可能会更改父实体的 ETag。
实体集(包括相关实体的集合)可以具有其自己的 ETag 值,其语义是特定于服务的。如果实体被添加到集合中或从集合中删除,或者集合中的实体发生更改,它通常会更改。通过导航属性访问的一组相关实体的 ETag 可能与包含导航属性的实体的 ETag 不同。
在现有资源上的数据修改请求或绑定到现有资源的操作请求可能需要乐观并发控制。服务应通过使用 [OData-VocCore] 中的 Core.OptimisticConcurrency 和 [OData-VocCap] 中的 Capabilities.NavigationRestrictions(嵌套属性 OptimisticConcurrencyControl)进行注释来公布此信息。
如果对资源需要乐观并发控制,则服务必须在对该资源的 GET 请求的响应中包含 ETag 头,并且可以在包含该资源的响应中以特定于格式的方式包含 ETag。
响应中的 ETag 头的存在本身并不意味着资源需要乐观并发控制;ETag 可以仅用于缓存和/或条件 GET 请求。
如果在数据修改请求或操作请求的 If-Match 或 If-None-Match 标头中指定了 ETag 值,则仅在满足 If-Match 或 If-None-Match 条件时才会调用该操作。
如果客户端在需要乐观并发控制的资源的数据修改请求或操作请求中没有指定 If-Match 请求头,则服务将以 428 Precondition Required 响应,并确保不会因请求而导致任何可观察的更改。客户端可以尝试通过指定值为 * 的 If-Match 来禁用乐观并发控制。服务可能会拒绝此类请求。
对于包含 OData-Version 标头值为 4.01 的请求,在更新请求的请求正文中指定的任何 ETag 值必须为 * 或与正在更新的记录的当前值匹配。
11.4.1.2 处理 DateTimeOffset 值
服务应尽可能保留 Edm.DateTimeOffset 值的偏移量。但是,如果底层存储不支持偏移量,服务可能会强制将值规范化为某个常见的时区(例如 UTC),在这种情况下,将返回带有该时区偏移量的结果。如果服务规范化了值,则对于未在规范值的时区中声明的文字值,它必须失败评估查询函数 year、month、day、hour 和 time。
11.4.1.3 处理在元数据中未公开的属性
客户端必须准备好接收实体或复杂类型实例中未在元数据中公开的其他属性,即使对于未标记为开放的类型也是如此。通过使用 PATCH 更新实体,客户端可以确保如果在更新请求中省略了这些属性的内容,这些属性值不会丢失。
11.4.1.4 处理完整性约束
服务可能会强制执行跨实体完整性约束。某些引用约束,例如要求使用相关实体创建实体,可以通过在创建实体时创建或链接相关实体来满足。其他约束可能需要以全部或无的方式处理多个更改。
11.4.1.5 从数据修改请求返回结果
客户端可以使用返回首选项头来请求在创建、更新或 upsert 操作期间返回创建或修改的资源。如果没有这样的头,则服务应返回已创建或修改的内容,除非该资源是流属性值。
除了更新流媒体实体的更新外,在返回更新结果时,服务必须返回与后续检索相同资源的请求的相同内容。对于更新媒体实体流,非空响应主体的内容必须是已更新的媒体实体。
返回单个结构化类型实例或结构化类型实例的集合的请求可以指定系统查询选项 expand 和
select。
返回集合的请求可以指定系统查询选项 $filter。
如果存在其中一个查询选项,并且没有指定返回首选项,则这意味着返回=表示性首选项。
如果存在其中一个查询选项,并且服务返回了表示性,则服务必须应用指定的查询选项。如果无法适当地应用指定的查询选项,则服务不得仅因存在这些查询选项而导致请求失败,而应返回 204 No Content。
11.4.2 创建实体
要在集合中创建实体,客户端向该集合的URL发送POST请求。POST请求体必须包含单个有效的实体表示。
实体表示可以包含对现有实体的引用,以及新相关实体的内容,但不能包含现有相关实体的内容。操作的结果是具有与所有包含的现有实体引用以及内联创建的所有相关实体关系的实体。如果实体的键属性包括直接相关实体的键属性,则这些相关实体必须被包括,可以作为对现有实体的引用或新相关实体的内容。
实体也可以通过 Upsert 操作创建。
如果集合的目标 URL 是导航链接,则新实体自动链接到包含导航链接的实体。
如果目标 URL 以类型转换段终止,则该段必须指定集合的类型或派生自集合类型的类型,并且实体必须以指定的类型创建。
要创建开放实体(开放类型的实例),除了元数据中指定的属性值之外,还可以在请求体中发送额外的属性值。服务必须将这些视为动态属性,并将它们添加到创建的实例中。
如果要创建的实体不是开放实体,则不应在请求体中发送除元数据中指定的属性值之外的额外属性值。如果无法持久化请求中指定的所有属性值,服务必须失败。
服务计算的属性(使用 Core.Computed 注解,参见 [OData-VocCore])和通过引用约束与主实体的属性关联的属性可以省略,如果在请求中包括这些属性,则必须忽略它们。
在请求中省略的具有定义默认值的属性、可为空的属性和省略的集合值属性将被设置为默认值、null 或空集合。
成功完成后,响应必须包含一个 Location 头,该头包含所创建实体的编辑 UR L或读取 URL。
成功完成后,服务必须响应为 201 Created,并包含所创建实体的表示,或者如果请求包括 Prefer 头并且值为 return=minimal,并且没有包括系统查询选项 select 和
expand,则服务必须响应为 204 No Content。
11.4.2.1 创建实体时链接相关实体
在单个请求中创建一个具有指向现有实体的链接的新实体,客户端在请求体中包含对相关实体的引用。
引用相关实体的表示形式是具体格式特定的。
例如:使用 JSON 格式,4.0 客户端可以通过在 DirectReports 导航属性上应用 odata.bind 注释来创建一个具有两个现有员工链接的新经理实体
{
"@odata.type": "#Northwind.Manager",
"ID": 1,
"FirstName": "Pat",
"LastName": "Griswold",
"DirectReports@odata.bind": [
"http://host/service/Employees(5)",
"http://host/service/Employees(6)"
]
}
例如:使用 JSON 格式,4.01 客户端可以通过在 DirectReports 导航属性中的实体 ID 中包含实体 ID 来创建一个具有两个现有员工链接的新经理实体
{
"@type": "#Northwind.Manager",
"ID": 1,
"FirstName": "Pat",
"LastName": "Griswold",
"DirectReports": [
{"@id": "Employees(5)"},
{"@id": "Employees(6)"}
]
}
成功完成操作后,服务将创建所请求的实体并将其关联到所请求的现有实体。
如果集合创建实体的目标 URL 与 POST 体提供的绑定信息与请求 URL 提供的隐式绑定信息相矛盾,则请求必须失败,并且服务将以 400 Bad Request 响应。
操作失败后,服务不得创建新实体。特别地,服务不得以部分有效的状态创建实体(导航属性未设置)。
操作失败后,服务不得创建新实体。特别是,服务绝不能创建处于部分有效状态的实体(未设置导航属性)。
11.4.2.2 创建实体时创建相关实体
包含相关实体的创建请求,使用适当的内联表示来表示,称为“深度插入”。
当嵌套在深度插入中时,媒体实体必须包含其媒体流的 base64url 编码表示作为虚拟属性 $value。
处理每个包含的相关实体时,将遵循创建实体的规则,就好像它们被发布到原始目标URL并扩展到该相关实体的导航路径一样。
成功时,服务必须创建所有实体并将它们关联起来。如果服务以 201 Created 响应,响应必须扩展到至少与深度插入请求中的级别相同。
客户端可以通过使用 [OData-VocCore] 中定义的 Core.ContentID 术语,将 id 与请求中的各个嵌套实体相关联。响应中的实体应使用与请求中指定的相同的 Core.ContentID 值进行注释。服务应该通过 Capabilities.DeepInsertSupport 术语(在 [OData-VocCap] 中定义)宣传深度插入的支持,包括返回 Core.ContentID 的支持;通过 Capabilities.DeepInsertSupport 宣传支持的服务必须返回插入或更新的实体的 Core.ContentID。
不支持深度插入操作的 continue-on-error 首选项。
失败时,服务不得创建任何实体。
11.4.3 更新实体
为了更新一个单个实体,客户端需要向标识实体的 URL 发起一个 PATCH 或 PUT 请求。服务端可以限制更新请求只能针对实体的编辑 URL。
服务端应该支持使用 PATCH 作为首选的更新实体方法。PATCH 通过只直接修改客户端指定的那些值,提供了客户端和服务端之间更好的容错性。
根据[RFC5789]中定义的语义,PATCH 的目的是将请求有效载荷中的内容与实体的当前状态合并,仅将更新应用于请求体中指定的那些组件。对应可更新属性的有效载荷中提供的集合属性和基元属性必须替换实体或复杂类型中相应属性的值。除非是由于提供的属性引起的更改而导致的副作用,否则不得直接更改包含实体或复杂属性的缺少属性,包括动态属性。
服务端可以额外支持 PUT,但应该意识到在往返属性时可能会丢失数据,而客户端事先可能不知道这些属性,比如开放或添加的属性,或者在元数据中未指定的属性。支持 PUT 的服务端必须使用请求体中指定的值替换结构性属性的所有值。未在关系约束中定义为依赖属性的丢失的非键、可更新的结构性属性必须设置为其默认值。在PUT请求中省略了没有由服务端生成或默认值的非空属性会导致 400 Bad Request 错误。丢失的动态结构性属性必须被删除或设置为 null。
对于带有 OData-Version 头的请求(值为 4.01 或更高版本),媒体实体的媒体流可以通过指定以 base64url 编码表示的媒体流作为虚拟属性 $value 来更新。
更新一个通过引用约束与主要实体的键属性相关的从属性,将关系更新为指向具有指定键值的实体。如果不存在这样的实体,则更新失败。
更新一个通过从属性在依赖实体上与主要实体通过引用约束相关联的主要属性将更新从属性。
在元数据中标记为只读的键和其他属性(包括计算属性)以及不与主要实体的键属性相关联的从属性可以在请求中省略。如果请求包含这些属性的值,服务端在应用更新时必须忽略该值。如果插入或更新包含一个当前无法由用户更改的可更新属性的新值(例如给定对象的状态或用户的权限),则服务端必须返回错误。如果指定的值与属性的值匹配,服务端可以在这种情况下返回成功。客户端应该使用 PATCH 并且只指定意图更改的那些属性。
在更新实体时无法更改实体的 id 和 entity type。然而,根据特定格式的规则,在应用更新时可能需要在有效载荷中提供实体 id 和 entity type 的值。
对于带有 OData-Version 头的请求(值为 4.01 或更高版本),如果请求体中的实体表示包括 ETag 值,那么更新操作不会执行,并且如果提供的 ETag 值不是*并且与实体的当前 ETag 值不匹配,应返回 12 Precondition Failed。对于包含 OData-Version 头值为 4.0 的请求,应忽略请求体中的 ETag 值。
如果一个更新操作既指定了与单值导航属性的绑定,又指定了与相同导航属性根据键属性相关联的从属性,则从属性将被忽略,并且关系将根据绑定中指定的值进行更新。
如果被更新的实体是开放的,那么可以在请求体中发送超出元数据中指定或在之前的请求中返回的属性值之外的其他属性值。服务端必须将这些属性视为动态属性。
如果被更新的实体不是开放的,那么应不在请求体中发送超出元数据中指定或在之前的请求中返回的属性值之外的其他属性值。如果服务端无法持久化请求中指定的所有可更新属性值,那么服务端必须失败。
成功完成后,服务端会以 200 OK 并使用更新后的实体的表示形式或 204 No Content 进行响应。客户端可以通过指定 Prefer 头部的值为 return=representation,或通过指定系统查询选项 select 或
expand 来请求响应中包含一个实体体。如果服务端使用 ETags 进行乐观并发控制,响应中的实体必须包含 ETags。
11.4.3.1 实体更新
当使用 OData 版本 4.0 发送带有值为 4.0 的 OData-Version 头部的更新请求时,禁止通过内联内容包含相关实体。此类请求可以包含导航属性的绑定信息。对于单值导航属性,这将替换关系;对于集合值导航属性,这将添加到关系中。
如果使用 OData 版本 4.01 或更高的OData-Version 头部的负载,可以包含嵌套实体和实体引用,以指定完整的关联实体集,或者可以使用嵌套的增量负载表示已添加、删除或更改的相关实体。此类请求被称为"深度更新"。如果嵌套集合与展开的导航属性相同,则在成功的更新请求中指定的嵌套实体和实体引用集合表示了根据该关系应关联的实体的完整集合,并且不得包含已添加的链接、已删除的链接或已删除的实体。
示例 78:使用 JSON 格式,可以使用 4.01 PATCH 请求更新经理实体。在更新后,经理有三个直接下属:两名现有员工和一名名为 Suzanne Brown 的新员工。员工 6 的姓氏更新为 Smith。
{
"@type":"#Northwind.Manager",
"FirstName" : "Patricia",
"DirectReports": [
{
"@id": "Employees(5}"
},
{
"@id": "Employees(6}",
"LastName": "Smith"
},
{
"FirstName": "Suzanne",
"LastName": "Brown"
}
]
}
如果嵌套集合在导航属性上表示为增量注释,则集合包含要添加或更改的成员,并且可能包含已删除的实体(不再属于集合的实体),使用增量负载格式。如果删除的实体指定了删除原因,则该实体将从集合中删除并删除,否则它将从集合中删除,并且仅当关系被包含时才删除。已删除实体的非键属性将被忽略。嵌套集合不得包含已添加或已删除的链接。如果请求包含嵌套的增量集合,则必须指定 PATCH 动词。
如果嵌套实体具有与现有实体相同的 ID 或键字段,则根据 PUT 或 PATCH 请求的语义来更新现有实体。具有没有 ID 或键字段的嵌套实体,或者其 ID 或键字段与现有实体不匹配的嵌套实体,将被视为插入操作。如果嵌套集合不表示包含关系且没有导航属性绑定,则此类实体必须包含指定新实体将被创建的实体集的上下文 URL。如果任何嵌套实体同时包含 ID 和键字段,它们必须标识相同的实体,否则请求无效。
示例 79:使用 JSON 格式,可以使用 4.01 PATCH 请求指定嵌套增量表示来:
- 删除员工 3 并删除链接
- 删除与员工 4 的链接并不删除它
- 添加与员工 5 的链接
- 更改员工 6 的姓氏并在需要时链接到它
- 添加名为“Suzanne Brown”的新员工并链接到它
{
"@type": "#Northwind.Manager",
"FirstName": "Patricia",
"DirectReports@delta": [
{
"@removed": {
"reason": "deleted"
},
"@id": "Employees(3)"
},
{
"@removed": {
"reason": "changed"
},
"@id": "Employees(4)"
},
{
"@id": "Employees(5)"
},
{
"@id": "Employees(6)",
"LastName": "Smith"
},
{
"FirstName": "Suzanne",
"LastName": "Brown"
}
]
}
客户端可以通过使用在 [OData-VocCore] 中定义的 Core.ContentID 术语来将 ID 与请求中的单个嵌套实体关联起来。响应使用与请求中指定的相同的 Core.ContentID 值对实体进行注释的服务应该返回状态码 200 OK。服务应该通过 [OData-VocCap] 中定义的 Capabilities.DeepUpdateSupport 术语来宣传支持深度更新,包括支持返回 Core.ContentID。
不支持 continue-on-error 首选项用于深度更新操作。
在失败时,服务不得应用请求中指定的任何更改。
注意:由于 Markdown 不支持 JSON 语法高亮,上述示例的 JSON 部分没有着重表示,但可以通过引用代码块来区分。
11.4.4 创建或更新实体
当客户端向指定的有效 URL 发送一个更新请求,该 URL 标识了一个尚不存在的单个实体时,就会发生创建或更新操作(upsert)。在这种情况下,服务端必须将该请求处理为创建实体的请求,或者完全拒绝该请求。
不支持对媒体实体、单值非包含导航属性或由服务生成键值的实体进行创建或更新操作。如果服务端收到一个更新请求,该请求的 URL 标识了这样一个实体,并且该实体尚不存在,服务端必须拒绝该请求。
如果可空的单例实体支持创建或更新操作,服务端应该通过使用术语 Capabilities.UpdateRestrictions(嵌套属性 Upsertable 的值设置为 true)在单例实体上进行注解,来将这一特性进行广告化,该术语在[OData-VocCap]中定义。
服务端在处理创建或更新请求时,必须忽略键和其他不可更新的属性,以及与主体实体的键属性无关的从属属性。
为了确保更新请求不被当作插入请求处理,客户端可以在更新请求中指定 If-Match 头。如果更新请求包含 If-Match头,服务端必须将其视为更新请求,而不是插入请求。
如果在请求中指定了 If-None-Match 头的值为*,则不得将 PUT 或 PATCH 请求视为更新请求。
11.4.5 删除实体
要删除一个个别实体,客户端向标识该实体的URL发送一个 DELETE 请求。服务端可以限制仅允许对实体的编辑 URL 进行删除操作。
请求体应为空。如果可空的单例实体支持删除操作,服务端应该通过使用术语 Capabilities.DeleteRestrictions(嵌套属性 Deletable 的值设置为 true)在单例实体上进行注解,来将这一特性进行广告化,该术语在[OData-VocCap]中定义。
成功完成删除操作后,响应必须为 204 No Content,并且不包含响应体。
当删除一个实体时,服务端必须隐式地删除与该实体的关系,客户端无需显式地删除这些关系。
如果完整性约束要求,服务端可以隐式地删除或修改相关实体。如果完整性约束在 $metadata 中使用 ReferentialConstraint 元素声明,则服务端必须根据所声明的完整性约束来修改相关实体,例如删除从属实体或将从属属性设置为null或其默认值。
其中一种完整性约束是在实体类型的键定义中使用导航属性。如果删除与“键”实体存在关联的主体实体,那么也会删除从属实体。
11.4.6 修改实体之间的关系
实体之间的关系通过导航属性来表示,详见数据模型。导航属性的 URL 约定详见[OData‑URL]。
11.4.6.1 添加到集合导航属性的引用
成功的 POST 请求将关系添加到导航属性的引用集合中。请求体必须包含一个唯一标识要添加的实体的实体引用。详细信息请参阅相应的格式文档。
成功完成后,响应必须为 204 No Content,并且不包含响应体。
请注意,如果两个实体在请求之前已经存在关联,请求也会成功执行。
11.4.6.2 删除实体的引用
成功的 DELETE 请求将删除到相关实体的关系的 URL 表示。
在 OData 4.0 中,在集合值导航属性内部被删除的实体引用是表示相关引用集合的 URL,可以通过 $id 查询选项来标识待删除的引用。OData 4.01 服务还支持使用表示待删除的集合成员的引用的 URL,该引用由键来标识,详见[OData‑URL]。
对于单值导航属性,不能指定 $id 查询选项。
DELETE 请求不得违反数据模型中的任何完整性约束。
成功完成后,响应必须为 204 No Content,并且不包含响应体。
11.4.6.3 更改单值导航属性中的引用
成功的 PUT 请求将单值导航属性的引用资源更改为相关实体。请求体必须包含一个唯一标识要关联的现有实体的实体引用。详细信息请参阅相应的格式文档。
成功完成后,响应必须为 204 No Content,并且不包含响应体。
或者,也可以通过在源实体的更新中包含新目标实体所需的绑定信息来更新关系。此绑定信息是特定格式的,详见[OData-JSON]中的详细信息。
如果单值导航属性在实体类型的键定义中被使用,那么它将无法更改,请求必须以 405 Method Not Allowed 或其他合适的错误失败。
11.4.6.4 替换集合导航属性中的所有引用
成功的 PUT 请求将集合导航属性的引用资源替换为一组相关的实体。请求体必须以与GET请求到导航属性的引用资源返回的格式相同的实体引用集合形式存在。
成功的 DELETE 请求将从集合导航属性的引用资源中删除所有相关引用。
11.4.6.4 替换集合值导航属性中的所有引用
对集合值导航属性的参考资源的成功 PUT 请求将替换相关实体集。请求正文必须包含实体引用的集合,其格式与 对导航属性的引用资源的 GET 请求返回的格式相同。
对集合值导航属性的引用资源的成功 DELETE 请求将从集合中删除所有相关引用。
11.4.7 管理媒体实体
一个媒体实体必须有一个源 URL,该 URL 可用于读取媒体流,并且可以有一个媒体编辑 URL,该 URL 可用于写入媒体流。
因为一个媒体实体同时具有媒体流和标准实体属性,所以需要特殊处理。
11.4.7.1 创建媒体实体
向媒体实体的实体集合发出 POST 请求可以创建一个新的媒体实体。请求体必须包含媒体值(例如照片),其媒体类型必须在 Content-Type 头中指定。请求体总是被解释为媒体值,即使它具有服务支持的 OData 格式的媒体类型。在创建媒体实体时,不可能设置媒体实体的结构属性。
成功完成后,响应必须包含 Location 头,其中包含所创建媒体实体的编辑 URL。
成功完成后,如果请求中包含优先头,其值为 return=minimal,则服务端响应 201 Created 或 204 No Content。
11.4.7.2 更新媒体实体流
向媒体实体的媒体编辑 URL 发出成功的 PUT 请求会更改实体的媒体流。
如果实体对媒体流包含 ETag 值,客户端必须在 If-Match 头中包含 ETag 值。
请求体必须包含实体的新的媒体值,其媒体类型必须在 Content-Type 头中指定。
成功后,服务端必须响应 204 No Content 和空 body,或者如果客户端指定了偏好 return=representation,则响应 200 OK,在这种情况下,响应体必须包含更新后的媒体实体。
11.4.7.3 删除媒体实体
如“删除实体”中所述,对实体的编辑 URL 或其媒体流的编辑 URL 发出成功的 DELETE 请求会删除媒体实体。
删除媒体实体也会删除与该实体关联的媒体。
11.4.8 管理流属性
实体可以有一个或多个流属性。流属性是 Edm.Stream 类型的属性。
流属性的值通常不出现在实体有效负载中。相反,这些值通常是通过 URL 来读取或写入的。
11.4.8.1 更新流值
对流属性的编辑 URL 成功的 PUT 请求会更改与该属性关联的媒体流。
如果流元数据包含 ETag 值,客户端应该在 If-Match 头中包含 ETag 值。
请求正文必须包含流的新媒体值,其媒体类型必须在 Content-Type 头中指定。它可以有长度为零的 Content-Length 来设置流数据为空。
流属性可以使用注解 TERM Core.AcceptableMediaTypes 来指定可接受的媒体类型列表,参见 [OData-VocCore]。
成功后,服务必须响应 204 无内容和空正文,或者如果客户端指定了偏好 return=representation,则响应体必须包含流的更新后的媒体值,状态码为 200 OK。
客户端可以通过修改流属性的编辑 URL 或读取 URL 来改变流属性和媒体流之间的关联。支持这种功能的服务应该用 [OData-VocCap] 中定义的术语 Capabilities.MediaLocationUpdateSupported 对流属性进行注解。
11.4.8.2 删除流值
对流属性的编辑 URL 成功的 DELETE 请求将尝试将属性设置为 null,如果属性不可为空则会导致错误。
尝试请求值为 null 的流属性会得到 204 无内容响应。
11.4.9 直接管理值和属性
可以用 URL 显式寻址值和属性。属性的编辑 URL 是实体编辑 URL 追加了指定单个属性的路径段。编辑 URL 允许单独修改属性。有关寻址单个属性的详细信息,请参阅 [OData‐URL]。
11.4.9.1 更新原始属性
对原始属性的编辑 URL 的成功 PUT 请求会更新该属性的值。消息体必须包含根据指定格式格式化的新值的单个属性。
对原始属性原始值的编辑 URL 的成功 PUT 请求用有效负载中指定的原始值更新该属性。有效负载必须按属性原始值的适当内容类型进行格式化。
这些规则适用于常规属性和动态属性。
成功完成后,服务响应 200 OK 或 204 无内容。客户端可以通过指定 Prefer 标头值为 return=representation 来请求响应体中应包含正文。
如果属性不可更新,服务必须返回错误。
11.4.9.2 将值设置为 null
对结构属性的编辑 URL 的成功 DELETE 请求,或对原始属性的原始值的编辑 URL 的成功 DELETE 请求,会将该属性设置为 null。请求正文会被忽略,应该为空。
对不可为空值的 DELETE 请求必须失败,并且服务应响应 400 错误请求或其他适当的错误。
这些规则适用于常规属性的值和动态属性的值。缺少的动态属性定义为与值为 null 的动态属性相同。所有动态属性都是可为空的。
成功时,服务必须以 204 空内容响应,并返回空正文。
如果属性不可更新,服务必须返回错误。
用 null 值更新原始属性或复杂属性也会将该属性设置为 null。
11.4.9.3 更新复杂属性
对复杂类型属性的编辑 URL 的成功 PATCH 请求会更新该属性。请求正文必须包含目标复杂类型的单个有效表示。
服务必须只直接修改 PATCH 请求有效负载中指定的复杂类型的那些属性。
服务还可以额外支持客户端将 PUT 请求发送到指定复杂类型的 URL。在这种情况下,服务必须用请求正文中指定的值完全替换整个复杂属性,并将所有未指定的属性设置为其默认值。
成功完成后,服务响应 200 OK 或 204 无内容。客户端可以通过指定 Prefer 标头值为 return=representation 来请求响应体中应包含正文。
如果属性不可更新,服务必须返回错误。
11.4.9.4 更新集合属性
对集合属性的编辑 URL 的成功 PUT 请求会更新该集合。消息正文必须包含所需的新值,格式化为根据指定格式的集合属性。
服务必须将整个值替换为请求正文中提供的值。
对集合属性的编辑 URL 的成功 POST 请求会向集合添加一个项。请求的正文必须是一个要添加到集合中的单项。如果集合是有序的,该项会被添加到集合的末尾,并且可以使用 $index 来指定一个基于零的序号位置来插入新值,其中负值表示从集合末尾的序号位置。
对集合属性的编辑 URL 的成功 DELETE 请求会删除该集合中的所有项。
由于集合成员没有单独的标识,因此集合属性不支持 PATCH。
成功完成后,服务响应 200 OK 或 204 无内容。客户端可以通过指定 Prefer 标头值为 return=representation 来请求响应体中应包含正文。
如果属性不可更新,服务必须返回错误。
11.4.10 管理有序集合的成员
使用 Core.Ordered 术语(参见 [OData-VocCore])进行注解的集合具有稳定的顺序。可以通过对集合 URL 追加包含集合中项的从零开始基于序号的段来单独更新或删除有序的原始类型和复杂类型集合的成员。负的序号表示从集合末尾开始索引,其中 -1 表示集合中的最后一项。
可以使用实体的编辑 URL 来更新实体,不应该使用索引来寻址实体。
11.4.11 基于位置的插入
用 Core 注释的实体、复杂或原始类型的集合。PositionalInsert 术语(请参阅 [OData-VocCore] )支持使用index系统查询选项通过对集合 URL 的POST请求在特定位置插入项目 。
index系统查询选项的值 是要插入项目的从零开始的序数位置。集合中大于或等于插入位置的项目的顺序位置加一。负序数从集合末尾开始索引,-1 表示插入为集合中的最后一项。
示例 80:在第二个位置插入新的电子邮件地址
POST /service/Customers('ALFKI')/EmailAddresses?$index=1
Content-Type: application/json
{
"value": "alfred@futterkiste.de"
}
11.4.12 更新实体集合
可以通过向集合的资源路径提交 PATCH 请求来更新实体集合。请求正文必须是增量负载,并且集合的资源路径不能包含类型转换或筛选段,也不能包含影响结果形状的任何系统查询选项。
添加/更改的实体作为 upserts 应用,删除的实体作为删除。删除实体的非键属性会被忽略。顶层集合可以包含添加和删除的链接,根据更新实体时处理相关实体的规则更新内联表示的相关实体。
客户端可以通过在请求中使用 [OData-VocCore] 中定义的 Core.ContentID 术语将 id 与单个嵌套实体相关联。使用请求中指定的相同 Core.ContentID 值对响应中的实体进行注解的服务在响应 200 OK 时应该这样做。
服务应通过 [OData-VocCap] 中定义的 Capabilities.UpdateRestrictions 术语的 DeltaUpdateSupported 属性advertise支持使用增量负载更新集合,并且应通过 Capabilities.DeepUpdateSupport 术语的 ContentIDSupported 属性advertise支持返回 Core.ContentID,。
如果请求了响应,响应是一个增量负载,其结构和顺序与请求负载相同,表示应用的更改。
如果指定了 continue-on-error 首选项并且在处理更改时发生任何错误,则无论返回首选项如何,都必须返回增量响应,并且必须至少包含失败的更改。服务如下表示失败请求中的更改:
- 请求中的失败删除在响应中必须表示为实体或实体引用,并使用 Core.DataModificationException 术语进行注解,参见 [OData-VocCore]。如果删除的实体指定了删除的原因,则 failedOperation 的值必须为 delete,否则为 unlink。
- 请求中失败的插入在响应中必须表示为带有 Core.DataModificationException 术语的删除实体,failedOperation 的值为 insert。
- 请求中的失败更新在响应中应该使用 Core.DataModificationException 术语进行注解,failedOperation 的值为 update。
- 请求中的失败添加链接在响应中必须表示为带有 Core.DataModificationException 术语的删除链接,failedOperation 的值为 link。
- 请求中的失败删除链接在响应中必须表示为带有 Core.DataModificationException 术语的添加链接,failedOperation 的值为 unlink。
- 请求中的集合必须在响应中表示为一个集合,其中包含服务在处理请求后存在的集合的当前值和成员资格。
如果由于依赖关系失败导致单个更改失败,则它必须使用 Core.DataModificationException 术语进行注解,并且应指定响应代码 424(Failed Dependency)。
或者,可以使用谓词 PUT,在这种情况下,请求正文必须是实体集合的表示。在这种情况下,请求中提供的所有实体都作为 upserts 应用,请求中未提供的任何实体都会被删除。在这种情况下,如果指定了 continue-on-error 首选项,并且请求返回成功响应代码,则无论返回首选项如何,都必须返回响应,并且必须包含服务中存在的集合的完整成员资格和值。
如果未指定 continue-on-error 首选项,并且服务无法应用请求中的所有更改,则它必须返回错误响应,并且不得应用请求负载中指定的任何更改。
11.4.13 更新集合中的成员
可以通过向集合资源路径后追加 /$each
构造的 URL 提交 PATCH 请求,来更新集合中的成员。额外的路径段表明请求体描述的是对集合中的每个成员的更新,而不是对集合本身的更新。
集合的资源路径可能包含类型转换或过滤器段来获取集合的子集,参见 [OData‐URL]。
对于原始类型的集合,请求体必须是一个原始值。集合中的每个成员(可能被过滤后的成员)都会被更新为指定的原始值。
对于结构化类型的集合,请求体必须是一个该集合结构化类型实例的完整或部分表示。集合中每个成员(可能被过滤后的成员)都会使用 PATCH 语义被更新。结构化类型可能包括嵌套集合或增量集合,这种情况下,描述在“更新实体集合”中的语义适用。
示例 81: 将所有米色-棕色产品的颜色改为土色
PATCH /service/Products/$filter(@bar)/$each?@bar=Color eq 'beige-brown'
Content-Type: application/json
{
"Color": "taupe"
}
如果请求了响应,响应是一个集合有效负载,包含每个被请求识别的成员的更新后表示。 如果更新有效负载包含嵌套集合或嵌套增量集合,那么它们必须按“更新实体集合”中描述的方式包含在响应中。
客户端应注意,对于那些可以高效地将更新应用于(可能被过滤的)集合的服务来说,请求响应可能非常昂贵。
如果已经指定了 continue-on-error 首选项,那么服务可能在失败后继续处理更新。在这种情况下,服务必须返回一个至少包含更新失败的集合成员的响应,这些成员必须使用 Core.DataModificationException
项进行标注,failedOperation 的值为 update。
如果尚未指定 continue-on-error 首选项,而服务无法更新请求中标识的所有成员,则它必须返回错误响应,并且不应用任何更新。
11.4.14 删除集合中的成员
可以通过向集合的资源路径后追加 /$each
提交 DELETE 请求,来删除集合中的成员。额外的路径段表明集合本身不会被删除。
请求的集合资源路径可能包含类型转换或过滤器段来获取集合的子集。
示例 82: 删除所有超过 3 岁的产品
DELETE /service/Products/$filter(Age gt 3)/$each
如果路径标识实体集合,并且服务返回表示,则响应是一个增量响应,对于每个被删除的成员都包含一个已删除实体的表示。
如果集合是实体的集合,则客户端可以指定 continue-on-error 首选项,在这种情况下,服务可以在失败后继续处理删除。在这种情况下,服务必须返回一个响应,至少包含请求中标识的每个失败删除的实体或实体引用,这些实体必须使用 Core.DataModificationException
项进行标注,failedOperation 的值为 delete。
客户端应注意,对于那些可以高效地将删除应用于(可能被过滤的)集合的服务来说,请求响应可能非常昂贵。
如果尚未指定 continue-on-error 首选项,而服务无法删除请求中标识的所有实体,则它必须返回错误响应,并且不应用任何更改。
11.5 自定义操作
自定义操作(Actions 和 Functions)允许封装除了前面章节描述的简单 CRUD 之外的用于修改或请求数据的逻辑。参见 [OData-CSDLJSON] 或 [OData-CSDLXML] 中的 Action、ActionImport、Function 和 FunctionImport。
11.5.1 将操作绑定到资源
Actions 和 Functions 可以绑定到任何类型或集合,类似于面向对象编程中在类中定义方法。绑定操作的第一个参数是绑定参数。
绑定操作的命名空间限定名或别名限定名可以附加到任何标识类型与绑定参数类型匹配或派生的资源的 URL。该 URL 标识的资源用作绑定参数的值。只有元数据文档中定义的别名可以在 URL 中使用。
示例 83:函数 MostRecentOrder 可以绑定到任何标识 SampleModel.Customer 的 URL
<Function Name="MostRecentOrder" IsBound="true">
<Parameter Name="customer" Type="SampleModel.Customer" />
<ReturnType Type="SampleModel.Order" />
</Function>
示例 84:使用绑定参数 customer 的值为 http://host/service/Customers(6) 标识的实体来调用 MostRecentOrder 函数
GET http://host/service/Customers(6)/SampleModel.MostRecentOrder()
示例 85:函数 Comparison 可以绑定到任何标识实体集合的 URL
<Function Name="Comparison" IsBound="true">
<Parameter Name="in" Type="Collection(Edm.EntityType)" />
<ReturnType Type="Diff.Overview" />
</Function>
示例 86:在红色产品集合上调用 Comparison 函数
GET http://host/service/Products/$filter(Color eq 'Red')/Diff.Comparison()
11.5.2 将操作应用于集合中的成员
只有单值绑定参数的绑定操作可以通过在集合的资源路径后追加路径段 /$each,后跟正斜杠和绑定操作的命名空间限定名或别名限定名,应用于集合的每个成员。在这种情况下,集合成员的类型必须与绑定参数的类型匹配或派生自绑定参数的类型。
集合的资源路径可以包含类型转换或过滤段来筛选集合。
响应是一个集合,其成员是绑定操作结果类型的实例。如果绑定操作返回一个集合,则响应是一个集合的集合。
示例 87:在实体集 Customers 中的每个实体上调用 MostRecentOrder 函数
GET http://host/service/Customers/$each/SampleModel.MostRecentOrder()
客户端可以指定 continue-on-error 首选项,在这种情况下,服务可以在操作失败后继续处理操作。在这种情况下,服务必须返回一个响应,无论返回首选项如何,该响应至少包含请求中标识的且操作失败的成员。这些成员必须使用 Core.DataModificationException 术语进行注释,failedOperation 值为 invoke。
如果未指定 continue-on-error 首选项,并且服务无法对请求标识的所有实体调用操作,则它必须返回错误响应,并且不得对集合的任何成员应用操作。
11.5.3 在有效负载中宣传可用的操作
服务可以将绑定到特定实体或实体集合的 actions 和/或 functions 作为实体或实体集合在有效负载中的表示的一部分返回。操作或函数的表示取决于格式。
示例 88:对 http://host/service/Customers('ALFKI') 的 GET 请求,服务可能用一个包含与实体绑定的 SampleEntities.MostRecentOrder 函数的 Customer 响应
{
"@context": ...,
"CustomerID": "ALFKI",
"CompanyName": "Alfreds Futterkiste",
"#SampleEntities.MostRecentOrder": {
"title": "Most Recent Order",
"target": "Customers('ALFKI')/SampleEntities.MostRecentOrder()"
},
...
}
假设客户端知晓元数据的高效格式可以忽略操作和函数的有效负载,这些操作和函数的目标 URL 可以通过遵循 [OData‐URL] 中定义的标准约定从元数据计算得出。
服务可以通过将值设置为 null 来宣传某个函数或操作对于特定实例不可用。
示例 89:对客户 'ALFKI' 来说 SampleEntities.MostRecentOrder 函数不可用
{
"@context": ...,
"CustomerID": "ALFKI",
"CompanyName": "Alfreds Futterkiste",
"#SampleEntities.MostRecentOrder": null,
...
}
11.5.4 函数
函数是由 OData 服务公开的操作,必须返回数据并且必须没有可观察到的副作用。
11.5.4.1 调用函数
要调用绑定到资源的函数,客户端需要发出一个GET请求到函数的URL。函数的URL可以从之前返回的实体表示中获得,或者通过将命名空间限定的或别名限定的函数名追加到标识与函数的绑定参数类型相同或派生的资源类型的URL来构造。绑定参数的值是在追加函数名之前URL标识的资源的值,附加的参数值使用内联参数语法指定。如果从之前返回的实体表示中获得函数URL,应当使用以 @ 符号开头的参数别名。客户端必须检查获得的URL是否已经包含查询部分,并需要用 & 或 ? 适当地在参数之前加上。
服务可能额外地通过定义一个或多个默认命名空间支持使用未限定函数名调用函数,默认命名空间是通过 [OData-VocCore] 中定义的 Core.DefaultNamespace 来定义的。
函数可以在 filter 或 orderby 系统查询选项中使用。这些函数可以像上面描述的那样绑定到资源,或者通过指定命名空间限定的(或别名限定的)函数名直接调用。
filter 或 orderby中的参数值需要根据内联参数语法指定。
要通过函数导入调用函数,客户端需要发出一个GET请求到标识函数导入的URL,并使用内联参数语法传递参数值。函数导入的规范URL是服务根URL,后面追加函数导入的名称。服务可能支持在调用没有参数的函数导入时省略括号,但是为了最大的互操作性,也必须支持使用空括号调用函数导入。
如果函数是可组合的,则可以根据函数返回的类型将其他路径段追加到标识可组合函数(或函数导入)的URL,路径段可以适当地用于返回类型,例如,如果最后一个路径段是一个多值导航属性,则可以使用POST请求在标识的集合中创建新实体。
示例 90:向由可组合函数导入 MyShoppingCart 返回的购物车物品列表中添加新项
POST http://host/service/MyShoppingCart()/Items
...
传递给函数的参数值必须以 URL 字面量(对于基元值)或 JSON 格式的 OData 对象(对于复杂值或基元或复杂值的集合)来指定。实体类型的值作为包含属性子集或只包含实体引用的适当 JSON 格式实体来传递,这取决于函数。
如果集合值函数对于给定的参数值组合没有结果,响应是特定格式的空集合表示。如果可空返回类型的单值函数没有结果,服务返回 204 No Content。
如果非空返回类型的单值函数没有结果,服务返回 4xx。对于返回单个实体的函数,404 Not Found 是适当的响应代码。
对于可组合函数,当函数结果需要 4xx 响应时处理停止,否则继续。
以 root root 字面量作为前缀的函数导入可以在 filter 或
orderby 系统查询选项中使用,参见 [OData‐URL]。
11.5.4.1.1 内联参数语法
参数值通过附加以逗号分隔的参数值列表(用括号括在函数名称后面)来内联指定。
每个参数值都表示为格式为 Name=Value 的名称/值对,其中 Name 是函数参数的名称,Value 是参数值。
示例 91:调用 Sales.EmployeesByManager 函数,该函数通过函数 importEmployeesByManager 采用 单个 ManagerID 参数
GET http://host/service/EmployeesByManager(ManagerID=3)
示例 92:返回传递给Sales.SalesRegion函数 时 City 属性返回“Western”的所有客户
GET http://host/service/Customers?
filter=Sales.SalesRegion(City=
it/City) eq '西部'
可以使用参数别名 来代替内联参数值。使用参数别名的名称将别名的值指定为单独的查询选项。
示例 93: 通过函数 importEmployeesByManager 调用 Sales.EmployeesByManager 函数,并为ManagerID参数传递 3
GET http://host/service/EmployeesByManager(ManagerID=@p1)?@p1=3
服务还可以允许函数导入和URL最后一个路径段的函数的隐式参数别名。隐式参数别名是参数名,可选地在前面加上 @ 符号。使用隐式参数别名时,不应在函数(导入)名后追加括号。每个参数的值必须作为一个独立的查询选项来指定,选项名是参数别名。如果参数名与系统查询选项名(不含可选的 $ 前缀)相同,则参数名必须加上 @ 符号作为前缀。
示例 94: 通过函数 importEmployeesByManager 调用 Sales.EmployeesByManager 函数,并使用隐式参数别名为ManagerID参数传递 3
GET http://host/service/EmployeesByManager?ManagerID=3
使用 [OData-VocCore] 中定义的 Core.OptionalParameter 术语注解的非绑定参数可以省略。如果注解了且注解指定了 DefaultValue,则省略的参数被解释为具有默认值。如果省略了且注解没有指定默认值,服务可以自由解释省略的参数。
11.5.4.2 函数重载解析
同一个函数名可以在模式中多次使用,每次具有不同的参数集。对于未绑定重载,函数名和无序的参数名集合必须唯一标识一个特定的函数重载。对于绑定重载,函数名、绑定参数类型和非绑定参数的无序名称集合必须唯一标识一个特定的函数重载。
所有未绑定重载必须具有相同的返回类型。此外,具有给定绑定参数类型的所有绑定重载也必须具有相同的返回类型。
如果函数已绑定且绑定参数类型是继承层次结构的一部分,则基于函数名之前的 URL 段类型来选择函数重载。可以使用类型转换段来选择层次结构中特定类型上定义的函数,参见 [OData‐URL]。
非绑定参数可以通过使用 [OData-VocCore] 中定义的 Core.OptionalParameter 注解它们来标记为可选的。所有标记为可选的必须排在任何未标记为可选的参数之后。
如果满足以下条件,则选择一个函数重载:
- 指定的参数集完全匹配一个函数重载;或
- 指定的参数集匹配包括全部非可选参数在内的一个函数重载的一个子集。
服务应该避免歧义,即函数名、非可选非绑定参数的无序集合加上绑定重载的绑定参数类型应当唯一标识一个特定的函数重载。如果存在歧义,服务可以返回 400 Bad Request 和一个说明请求有歧义的错误响应主体。
11.5.5 Actions
Actions 是 OData 服务公开的操作,调用它们时可能产生副作用。Actions 可能返回数据,但不能与其他路径段继续组合。
11.5.5.1 调用 Action
要调用绑定到某个资源的 Action,客户端需要通过 POST 请求访问 Action 的 URL。Action 的 URL 可以从之前返回的实体表示中获取,也可以通过在标识与 Action 绑定参数类型相同或派生的资源类型的 URL 后面追加 Action 的命名空间/别名限定名来构造。绑定参数的值是 Action URL 前面的资源所标识的资源,只有非绑定参数的值按照特定格式在请求体中传递。
服务还可以通过在 [OData-VocCore] 中定义的 Core.DefaultNamespace 条款来支持使用非限定的 Action 名调用 Actions。
要通过 Action 导入调用 Action,客户端需要对标识 Action 导入的 URL 发起 POST 请求。 Action 导入的规范 URL 是服务根 URL 加上 Action 导入的名称。通过 Action 导入调用 Action 时,所有参数值都必须按照特定格式在请求体中传递。
可以省略请求体中的可空或使用 [OData-VocCore] 中的 Core.OptionalParameter 注释的非绑定参数。如果省略的不是可空参数,则必须解释为 null 值。如果省略的是使用注释且注释指定了默认值的参数,则解释为默认值。如果省略的使用了注释但注释没有指定默认值,服务可以自由解释该省略的参数。注:一个可空的非绑定参数相当于被注释为可选参数并默认为 null。
4.01 服务必须支持无非绑定参数的 Actions 以及无参 Action 导入,允许不传请求体或传一个代表无参数的请求体,格式由具体格式决定。可互操作的客户端应该总是包含请求体,即使调用无非绑定参数的 Actions 或无参的 Action 导入。
如果 Action 返回结果,客户端应该使用内容协商来请求所需的格式的结果,否则将使用默认内容类型。
客户端可以使用 return 首选项标头来请求 Action 的结果是否返回。
创建并返回单个实体的 Actions 遵循实体创建的规则,并返回包含所创建实体的编辑 URL 或读取 URL 的 Location 标头。
无返回类型的 Actions 在成功时响应 204 No Content。
要仅在绑定参数值(一个实体或实体集合)未修改时处理 Action,客户端需要包含 If-Match 标头并指定实体或实体集合的最新已知 ETag 值。集合的整体 ETag 值在集合响应的 ETag 标头中传输。
示例:使用 /Customers('ALFKI')
作为客户(或绑定参数)调用 SampleEntities.CreateOrder action。数量参数为 2、折扣码参数为 BLACKFRIDAY 的参数值在请求体中传递。只在客户的 ETag 仍然匹配时调用该 Action。
POST http://host/service/Customers('ALFKI')/SampleEntities.CreateOrder
If-Match: W/"MjAxOS0wMy0yMVQxMzowNVo="
{
"items": [
{ "product": 4001, "quantity": 2 },
{ "product": 7062, "quantity": 1 }
],
"discountCode": "BLACKFRIDAY"
}
11.5.5.2 Action 重载解析
同一个 Action 名称可以在一个模式中多次使用,前提是至多有一个非绑定的重载,每个绑定的重载指定不同的绑定参数类型。
如果 Action 被绑定且绑定参数类型是继承层次结构的一部分,则根据 Action 名之前的 URL 段的类型选择 Action 重载。可以使用类型转换段来选择在层次结构中定义在特定类型上的 Action,参见 [OData‐URL]。
11.6 异步请求
包含 respond-async
首选项的 Prefer 头允许客户端请求服务端异步处理数据服务请求。
如果客户端在请求中指定了 respond-async
,服务端可以异步处理该请求,并返回一个 202 Accepted 响应。如果请求没有包含 respond-async
首选项,服务端不能用 202 Accepted 响应数据服务请求。
返回 202 Accepted 的响应必须包含一个指向表示异步处理当前状态的状态监视资源的 Location 头,以及一个可选的 Retry-After 头,指示客户端应该在查询服务状态之前等待的时间(以秒为单位)。服务端可以在响应体中包含额外的状态信息。
对状态监视资源的 GET 请求如果异步处理还未完成,同样会返回 202 Accepted 响应。该响应必须再次包含 Location 头,并且可以包含 Retry-After 头以用于后续请求。Location 头和可选的 Retry-After 头的值与前一个请求返回的可能相同,也可能不同。
异步处理完成后,对状态监视资源的 GET 请求会返回 200 OK。对于 OData 4.01及更高版本的响应,或者包含非 application/http 的 Accept 头的 OData 4.0 请求,响应必须包含 AsyncResult 头。任何其他头以及响应体代表完成的异步操作的结果。如果状态监视的 GET 请求包含一个值为 4.0 的 OData-MaxVersion 头和没有 Accept 头或包含 application/http 的 Accept 头,那么最后的 200 OK 响应体必须表示为 HTTP 消息,如 [RFC7230] 中所述,它是完成的异步操作的完整 HTTP 响应。
对状态监视资源的 DELETE 请求表示请求取消异步处理。200 OK 或 204 No Content 响应表示异步处理已成功取消。客户端可以请求异步执行 DELETE。202 Accepted 响应表示取消正在异步处理;客户端可以使用返回的 Location 头(必须与初始请求的状态监视资源不同)来查询取消的状态。如果服务不支持删除请求,则返回 405 Method Not Allowed。
在成功对状态监视资源执行 DELETE 请求后,后续对同一资源的任何 GET 请求都会返回 404 Not Found。
如果异步请求因除消费者针对状态监视资源发出 DELETE 请求之外的其他原因被取消,则对状态监视资源的 GET 请求会返回 200 OK,响应体包含一个 HTTP 响应,状态码为 5xx 范围内的服务器错误,表示操作被取消。
服务端必须确保取消的请求不会产生任何可观察的变化。
如果客户端等待结果的时间太长,服务端会响应 410 Gone 或 404 Not Found。
状态监视资源的 URL 必须不同于任何其他资源的 URL。
11.7 批处理请求
批处理请求允许将多个独立请求组合成一个 HTTP 请求 payload。批处理请求 context 中的一个独立请求可以是一个元数据请求、数据请求、数据修改请求、操作调用请求或函数调用请求。
批处理请求作为一个 HTTP POST 请求提交到服务的批处理端点,该端点位于服务根目录下的$batch
URL。
批处理请求中的各个请求的语义与单独出现在批处理请求之外的请求语义相同。
批处理请求可以用本文档定义的多部分批处理格式或[OData-JSON]中定义的 JSON 批处理格式表示。
11.7.1 批处理请求头
使用多部分批处理格式的批处理请求必须包含一个 Content-Type 头,指定 content type 为 multipart/mixed
,并且包含[RFC2046]中定义的 boundary 参数。
POST /service/$batch HTTP/1.1
Host: odata.org
OData-Version: 4.0
Content-Type: multipart/mixed; boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b
<Multipart Batch request body>
使用JSON批处理格式的批处理请求必须包含一个 Content-Type 头,指定 content type 为application/json
。
POST /service/$batch HTTP/1.1
Host: odata.org
OData-Version: 4.01
Content-Type: application/json
<JSON Batch request body>
批处理请求应该包含适用的 OData-Version 头。
批处理请求应该包含一个 Accept 头,指定所需的批处理响应格式,可以是 multipart/mixed
或 application/json
。如果没有提供 Accept 头,服务应该以请求的 content type 响应。
如果批处理请求的请求头集合有效,服务必须返回一个 200 OK HTTP 响应代码,表示批处理请求已被接受以进行处理,但处理尚未完成。批处理请求主体中的各个请求随后可能会失败或格式错误;但是,这使得批处理实现能够流式传输结果。
如果服务收到具有无效请求头集的批处理请求,它必须返回 4xx 响应代码,并停止对批处理请求的进一步处理。
11.7.2 请求依赖关系
根据特定的批处理格式,批处理请求中的请求可能依赖于其他请求。
在 JSON 格式中,请求可以明确声明其依赖的必须先成功处理的其他请求。此外,请求可以指定为原子组的一部分,其成员要么全部成功,要么全部失败。如果一个请求失败,那么 JSON 格式中的任何依赖请求都将返回 424 Failed Dependency。
在多部分格式中,数据修改请求或操作调用请求可以组合成原子更改集的一部分。更改集外的操作按顺序执行,而更改集内的操作可以以任意顺序执行。
11.7.3 识别各个请求
批处理请求中的每个独立请求都可以分配一个请求标识符。请求标识符区分大小写,在批处理请求中必须唯一,并且必须满足 [OData-ABNF]中的 request-id 规则。
请求标识符的表示与批处理格式相关,各个请求需要标识符也与格式相关。
11.7.4 引用返回的实体
通过使用以$字符为前缀的请求标识符作为请求 URL 的第一段, 可以在后续请求的请求 URL 中引用插入请求创建的实体。
如果以为前缀的请求标识符与顶级系统资源的名称相同(
batch、crossjoin、
all、 entity、
root、id、
metadata 或根据 OData定义的其他系统资源- 请求中指定的协议版本 ),然后使用对顶级系统资源的引用。这种冲突可以通过例如仅使用数字请求标识符来避免。
服务还可以支持请求主体内的引用,在这种情况下,它们应该通过在应用于实体容器的 Capability.BatchSupport 术语中指定 ReferencesInRequestBodiesSupported 属性来宣传此支持,请参阅 [OData-VocCap]
11.7.5 引用实体的 ETag
服务可以支持在后续语句的If-Match或If-None-Match头中使用先前操作返回的ETag。服务应通过在应用于实体容器的Capabilities.BatchSupport注释术语中指定EtagReferencesSupported属性来声明对此的支持,见 [OData-VocCap]。
前一个操作的ETag可以通过使用以$字符为前缀的请求标识符作为If-Match或If-None-Match头的未加引号的值来引用。
11.7.6 从响应主体中引用值
服务可以支持在 URL 的查询部分或后续请求的请求主体中使用来自响应主体的值。值引用由一个 $ 字符组成,后跟前一个请求的请求标识符,并可选地后跟一个有效的 OData 路径。
如果 −前缀的请求标识符与查询表达式的预定义字面量(−前缀的请求标识符与查询表达式的预定义字面量(it、$root 或根据请求中指定的 OData 版本定义的其他字面量)相同,则使用预定义的字面量。例如,只使用数字请求标识符可以避免此冲突。
11.7.7 多部分批处理格式
多部分批处理格式表示为一种多部分媒体类型消息 [RFC2046],这是一种标准格式,允许表示多个部分,每个部分可能具有不同的内容类型。
11.7.7.1 多部分批处理请求体
多部分批处理请求的主体由一系列单独的请求和更改集组成,每个都表示为一个独特的正文部分(即在由两个破折号和内容类型标头中指定的边界参数的值组成的边界分隔符行之前,最后一个正文部分后跟一个由两个破折号、边界和另外两个破折号组成的结束边界分隔符行)。
表示单个请求的正文部分必须包含一个 Content-Type 标头,其值为 application/http。
表示更改集的正文部分本身必须是一个多部分文档(参见 [RFC2046]),对于更改集中的每个操作都有一个正文部分。表示更改集中操作的每个正文部分都必须指定一个 Content-ID 标头,其值为批处理请求中唯一的请求标识符。
出于历史原因,可以包含一个 Content-Transfer-Encoding 标头,其值为 binary,尽管 HTTP 不使用此标头,只在通过电子邮件传输时需要。客户端和服务都不应依赖此标头的存在。
如 [RFC2046] 中定义的那样,在多部分批处理请求体中,前言和尾声是有效的,但不赋予任何含义,因此必须被多部分批处理请求的处理器忽略。
批处理请求中各个请求的请求 URL 可以使用以下三种格式之一:
带方案、主机、端口和绝对资源路径的绝对 URI。
示例 98:
GET https://host:1234/path/service/People(1) HTTP/1.1
绝对资源路径和单独的 Host 标头
示例 99:
GET /path/service/People(1) HTTP/1.1
Host: myserver.mydomain.org:1234
相对于批处理请求 URI 的资源路径。
示例 100:
GET People(1) HTTP/1.1
服务必须支持这三种格式的个别请求的 URL。
URL 必须正确百分比编码。对于相对 URL,这意味着路径部分中的冒号,特别是在键值中,必须百分比编码以避免与方案分隔符混淆。查询部分中的冒号,即问号字符(?)之后,不需要百分比编码。
表示单个请求的每个正文部分都不得包含:
与身份验证或授权相关的 HTTP 标头
Expect、From、Max-Forwards、Range 或 TE 标头
批处理请求的处理器可以选择不允许在批处理请求内序列化的 HTTP 请求中使用其他 HTTP 构造。例如,处理器可以选择不允许此类 HTTP 请求使用分块编码。
示例 101:一个批处理请求,按列出的顺序包含以下各个请求:
- 一个查询请求
- 一个包含以下请求的更改集:
- 插入实体(Content-ID = 1)
- 更新实体(Content-ID = 2)
- 第二个查询请求
注意:为简洁起见,在示例中,请求主体被英文描述在<>括号内代替,并省略了 OData-Version 标头。
还要注意,GET 请求的 Host 标头后的两个空行是必需的:第一个是 GET 请求标头的一部分;第二个是 GET 请求的空正文,后跟 CRLF 根据 [RFC2046]。
POST /service/$batch HTTP/1.1
Host: host
OData-Version: 4.0
Content-Type: multipart/mixed; boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Length: ###
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
GET /service/Customers('ALFKI')
Host: host
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: multipart/mixed; boundary=changeset_77162fcd-b8da-41ac-a9f8-9357efbbd
--changeset_77162fcd-b8da-41ac-a9f8-9357efbbd
Content-Type: application/http
Content-ID: 1
POST /service/Customers HTTP/1.1
Host: host
Content-Type: application/json
Content-Length: ###
<新的客户的 JSON 表示>
--changeset_77162fcd-b8da-41ac-a9f8-9357efbbd
Content-Type: application/http
Content-ID: 2
PATCH /service/Customers('ALFKI') HTTP/1.1
Host: host
Content-Type: application/json
If-Match: xxxxx
Prefer: return=minimal
Content-Length: ###
<客户 ALFKI 的更改的 JSON 表示>
--changeset_77162fcd-b8da-41ac-a9f8-9357efbbd--
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
GET /service/Products HTTP/1.1
Host: host
--batch_36522ad7-fc75-4b56-8c71-56071383e77b--
11.7.7.2 引用新实体
可以在同一更改集中的后续请求的请求 URL 中引用 Insert 请求创建的实体。如果服务还支持跨更改集引用,则它们应通过在应用于实体容器的 Capabilities.BatchSupport 术语中指定 ReferencesAcrossChangeSetsSupported 属性来宣传此支持,参见 [OData-VocCap]。
示例 102:一个包含以下按列出顺序的操作的批处理请求:
一个包含以下请求的更改集:
- 插入一个新实体(Content-ID = 1)
- 插入第二个新实体(引用 Content-ID = 1 的请求)
POST /service/$batch HTTP/1.1
Host: host
OData-Version: 4.0
Content-Type: multipart/mixed; boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Length: ###
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: multipart/mixed; boundary=changeset_77162fcd-b8da-41ac-a9f8-9357efbbd
--changeset_77162fcd-b8da-41ac-a9f8-9357efbbd
Content-Type: application/http
Content-ID: 1
POST /service/Customers HTTP/1.1
Host: host
Content-Type: application/json
Content-Length: ###
<新的客户实体的 JSON 表示>
--changeset_77162fcd-b8da-41ac-a9f8-9357efbbd
Content-Type: application/http
Content-ID: 2
POST $1/Orders HTTP/1.1
Host: host
Content-Type: application/json
Content-Length: ###
11.7.7.3 引用 ETag
示例 103:按列出的顺序包含以下操作的批处理请求:
· 获取一名员工(Content-ID = 1)
· 仅在员工没有变动的情况下更新工资
POST /service/$batch HTTP/1.1
Host: host
OData-Version: 4.0
Content-Type: multipart/mixed; boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Length: ###
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-ID: 1
GET /service/Employees(0) HTTP/1.1
Host: host
Accept: application/json
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
Content-Type: application/http
Content-ID: 2
PATCH /service/Employees(0) HTTP/1.1
Host: host
Content-Type: application/json
Content-Length: ###
If-Match: $1
{
"Salary": 75000
}
--batch_36522ad7-fc75-4b56-8c71-56071383e77b--
11.7.7.4 处理多部分批处理请求
服务必须按收到的顺序处理批处理请求中的各个请求和更改集。除非使用显式或隐式值为true的 continue-on-error 首选项,否则在第一个错误时停止处理。
更改集中的所有请求都代表一个单一的更改单元,所以服务必须成功处理并应用更改集中的所有请求,否则不应用任何请求。由服务实现定义回滚语义,以撤消在同一更改集中另一个请求失败之前可能已应用的任何请求,从而应用这种全部或无的要求。服务可以以任何顺序执行更改集中的请求,并可以以任何顺序返回对各个请求的响应。 如果请求指定了请求标识符,则服务必须在相应响应中包含 Content-ID 报头及请求标识符,以便客户端可以关联请求和响应。
11.7.7.5 多部分批处理响应
对批处理请求的多部分响应必须包含值为 multipart/mixed 的 Content-Type 报头。
对多部分批处理请求的多部分响应的主体必须与多部分批处理请求主体结构上完全匹配,也就是说,对请求定义的相同多部分消息结构用于响应。这个规则有三个例外:
- 当更改集中的请求失败时,不会使用 multipart/mixed 媒体类型表示更改集响应。相反,返回一个单一响应,使用 application/http 媒体类型,适用于更改集中的所有请求,并且必须是一个有效的 OData 错误响应。
- 当发生处理请求的错误且未指定 continue-on-error 首选项,或指定为显式值为 false 时,会终止批处理的处理,错误响应是多部分响应的最后一部分。
- 异步处理的批处理请求可以返回中间结果,并以 202 Accepted 作为多部分响应的最后一部分结束。因此,如果批处理响应是多部分响应,则不能对批处理中的各个请求应用 respond-async 首选项。
对 JSON 批处理请求的多部分响应主体包含每个经处理或接受的请求的一个主体部分。各个主体部分的顺序不重要,因为每个主体部分都必须包含 Content-ID 报头,其值为相应请求对象的 id 名称/值对。
对批处理中操作的响应必须与批处理外完全相同的格式,如相应子部分中所述的数据服务请求。每个各别响应中的相对 URL 相对于相应各个请求的请求 URL。响应中的 URL 不得包含 $-prefixed 请求标识符。
例如,参考上面的批处理请求示例 101,假设除最后的查询请求外,所有请求都成功。在这种情况下,响应如下:
HTTP/1.1 200 Ok
OData-Version: 4.0
Content-Length: ####
Content-Type: multipart/mixed; boundary=b_243234_25424_ef_892u748
--b_243234_25424_ef_892u748
Content-Type: application/http
HTTP/1.1 200 Ok
Content-Type: application/json
Content-Length: ###
<JSON 表示具有键 ALFKI 的 Customer 实体>
--b_243234_25424_ef_892u748
Content-Type: multipart/mixed; boundary=cs_12u7hdkin252452345eknd_383673037
--cs_12u7hdkin252452345eknd_383673037
Content-Type: application/http
Content-ID: 1
HTTP/1.1 201 Created
Content-Type: application/json
Location: http://host/service.svc/Customer('POIUY')
Content-Length: ###
<新 Customer 实体的 JSON 表示>
--cs_12u7hdkin252452345eknd_383673037
Content-Type: application/http
Content-ID: 2
HTTP/1.1 204 No Content
Host: host
--cs_12u7hdkin252452345eknd_383673037--
--b_243234_25424_ef_892u748
Content-Type: application/http
HTTP/1.1 404 Not Found
Content-Type: application/xml
Content-Length: ###
<错误信息>
--b_243234_25424_ef_892u748—
11.7.7.6 异步批处理请求
通过在 Prefer 头中包含 respond-async 首选项,批处理请求可以异步执行。如果服务以多部分批处理响应响应,则它必须忽略批处理中各个请求的 respond-async 首选项。
成功执行批处理请求后,对状态监视器资源 URL 的审查请求的响应主体中返回对批处理请求的响应(参见异步请求)。
服务可以通过响应监视器资源的 GET 请求并在多部分响应的最后一部分包含 202 Accepted 响应,来返回异步执行的批处理的中间结果。客户端可以使用这个 202 Accepted 响应中返回的监视 URL 来继续处理批处理响应。
由于更改集以原子方式执行,所以不能在更改集中返回 202 Accepted。
例如,再次参考上面的示例 101,假设:
HTTP/1.1 202 Accepted
Location: http://service-root/async-monitor-0
Retry-After: ###
在审查监视 URL 时,批处理中只有第一个请求已完成处理,所有剩余的请求仍在处理中。请注意,实际的多部分批处理响应本身包含在 application/http 包装器中,因为它是对状态监视器资源的响应:
HTTP/1.1 200 Ok
Content-Type: application/http
HTTP/1.1 200 Ok
OData-Version: 4.0
Content-Length: ####
Content-Type: multipart/mixed; boundary=b_243234_25424_ef_892u748
--b_243234_25424_ef_892u748
Content-Type: application/http
HTTP/1.1 200 Ok
Content-Type: application/json
Content-Length: ###
<JSON 表示具有键 ALFKI 的 Customer 实体>
--b_243234_25424_ef_892u748
Content-Type: application/http
HTTP/1.1 202 Accepted
Location: http://service-root/async-monitor
Retry-After: ###
--b_243234_25424_ef_892u748--
一段时间后,客户端使用返回的监视 URL 进行第二次请求,不明确接受 application/http。批处理完全处理完毕,响应是最终结果。
HTTP/1.1 200 Ok
AsyncResult: 200
OData-Version: 4.0
Content-Length: ####
Content-Type: multipart/mixed; boundary=b_243234_25424_ef_892u748
--b_243234_25424_ef_892u748
Content-Type: multipart/mixed; boundary=cs_12u7hdkin252452345eknd_383673037
--cs_12u7hdkin252452345eknd_383673037
Content-Type: application/http
Content-ID: 1
HTTP/1.1 201 Created
Content-Type: application/json
Location: http://host/service.svc/Customer('POIUY')
Content-Length: ###
<新 Customer 实体的 JSON 表示>
--cs_12u7hdkin252452345eknd_383673037
Content-Type: application/http
Content-ID: 2
HTTP/1.1 204 No Content
Host: host
--cs_12u7hdkin252452345eknd_383673037--
--b_243234_25424_ef_892u748
Content-Type: application/http
HTTP/1.1 404 Not Found
Content-Type: application/xml
Content-Length: ###
<错误信息>
--b_243234_25424_ef_892u748—
12 安全考虑
本节为 OData 4.0 的应用程序开发人员、信息提供者和用户提供了一些起点,以便了解保护 OData 服务的指南。OData 是一个依赖于其他服务的 RESTful 多格式服务,因此从后者继承了安全增强和关注点两方面。
关于与 HTTP 相关的安全性问题,请参考 [RFC7231] 的相关章节(9. 安全考虑事项),以及对于 HTTP PATCH 方法,请参考 [RFC5789] 的相关章节(5. 安全考虑事项)。
12.1 安全认证
要求进行认证的 OData 服务应该支持使用 [RFC7617] 中定义的基本认证,并使用 HTTPS 以实现与通用客户端的最高互操作性。它们也可以支持其他认证方法。
13 一致性
OData 被设计成一套基于现有标准的约定,用于为常见功能提供通用表示。并非所有服务都支持协议中定义的所有约定;服务可根据其情景选择 OData 中定义的具有适合其方案的功能的约定作为其表示方法。
为了促进客户端/服务器之间的互操作性,此规范为 OData 服务定义了多个一致性级别,以及 OData 客户端在 OData 服务之间的互操作所需的最低要求。
13.1 OData 4.0 服务一致性级别
OData 4.0 定义了三个一致性级别。
注:一致性级别的设计与不同的服务情景对应。例如,符合 OData 定义的一个或多个数据格式的数据发布服务可以符合 OData 4.0 的最小一致性级别,而不支持任何其他功能。允许客户端对检索的数据具有更多控制权的服务可以符合 OData 4.0 的中级一致性级别。符合 OData 4.0 的高级一致性级别的服务可以预期可以在广泛的通用客户端范围内实现最多的功能互操作。
服务可以通过在其实体容器上注释使用 [OData-VocCap] 中定义的 Capabilities.ConformanceLevel 术语来宣布它们的一致性级别。
注:建议服务根据其预期的方案适当地支持超出其一致性级别的尽可能多的其他功能。
注意:鼓励服务支持超出其一致性级别的尽可能多的附加功能,以适合其预期场景。
13.1.1 OData 4.0 最小一致性级别
为符合 OData 4.0 的最小一致性级别,一个服务必须:
-
必须在服务根目录下发布一个服务文档(第 11.1.1 节)
-
必须返回符合 [OData-JSON] 格式的数据
-
必须在返回部分结果时使用服务器端分页(第 11.2.6.7 节),而不使用任何其他机制
-
必须返回适当的 OData-Version 头(第 8.1.5 节)
-
必须遵循以下的语义相关头部,否则请求失败
5.1. Accept(第 8.2.1 节)
5.2. OData-MaxVersion(第 8.2.7 节)
-
必须遵循 OData 的扩展性准则(第 6 节和所有子节)
-
必须根据 [OData-ABNF] 成功解析请求,对于任何受支持的系统查询选项,要么遵循规范,要么对于任何不支持的功能,返回 501 Not Implemented(第 9.3.1 节)
-
必须仅公开在 [OData-CSDLXML] 中定义的数据类型
-
为了正确使用服务,客户端不需要理解任何元数据或实例注解(第 6.4 节)、自定义头部(第 6.5 节)或负载中的自定义内容(第 6.2 节)
-
不能违反任何 OData 更新语义(第 11.4 节和所有子节)
-
不能违反任何其他 OData 定义的语义
-
应该支持 $expand(第 11.2.5.2 节)
-
应该在 $metadata 中发布元数据,根据 [OData-CSDLXML] 进行发布,并且可以根据 [OData-CSDLJSON] 进行发布(第 11.1.2 节)
-
必须支持受限修饰符的变体和首选值
-
必须在带有类型前缀的 URL 中支持枚举和时长字面量
如果还支持异步操作:
- 对于异步请求的最终响应,必须返回一个带有 OData-MaxVersion 值为 4.0 并且包含 application/http 的 Accept 头的 HTTP 消息。
- 可以在异步请求的最终响应中返回 AsyncResult 头部
为被认为是可更新的 OData 服务,服务还必须:
- 对于所有可更新或可删除的资源,必须根据 [OData-JSON] 显式或隐式地包含编辑链接。
- 必须支持将新实体以 POST 方式插入可插入的实体集(第 11.4.1.5 和 11.4.2.1 节)
- 必须支持将新关联实体以 POST 方式插入到可更新的导航属性(第 11.4.2 节)
- 必须支持 POST 到 $ref,将现有实体添加到可更新的关联集合(第 11.4.6.1 节)
- 必须支持 PUT 到 $ref,将现有的单个可更新相关实体设置(第 11.4.6.3 节)
- 必须支持 PATCH 到所有可更新资源的编辑 URL(第 11.4.3 节)
- 必须支持 DELETE 到所有可删除资源的编辑 URL(第 11.4.5 节)
- 必须支持 DELETE 到 $ref,从可更新的导航属性中删除对实体的引用(第 11.4.6.2 节)
- 必须支持在具有 ETag 的资源的更新/删除中使用 If-Match 头(第 11.4.1.1 节)
- 必须在对创建或插入操作返回 204 No Content 的响应中,返回带有编辑 URL 或读取 URL 的 Location 头(第 11.4.2 节)
- 在对返回 204 No Content 的创建或插入操作的响应中,必须包含 OData-EntityId 头(第 8.3.4 节)
- 必须支持 Upserts(第 11.4.4 节)
- 应该支持将 PUT 和 PATCH 用于单个基元属性(第 11.4.9.1 节)或复杂属性(第 11.4.9.3 节)
- 应该支持 DELETE 将单个属性设置为 null(第 11.4.9.2 节)
- 应该支持深度插入(第 11.4.2.2 节)
- 可以支持对集合成员进行基于集合的更新(第 11.4.13 节)或删除(第 11.4.14 节)
13.1.2 OData 4.0 中级一致性级别
为了符合 OData 中级符合级别,服务必须:
- 符合 OData 4.0 最低符合级别。
- 成功解析 [OData-ABNF],要么遵循规范,要么对于任何不支持的功能返回 501 未实施(章节 9.3.1)。
- 支持 $select(章节 11.2.5.1)。
- 根据 [OData‑URL],如果模型中存在派生类型,则支持向派生类型进行强制类型转换。
- 支持 $top(章节 11.2.6.3)。
- 在媒体实体上([OData‑URL] 中的章节 4.12)和单个属性上(章节 11.2.4.1)支持 /$value。
- 支持 $filter(章节 11.2.6.1)。
7.1. 在请求的实体集中的实体属性上支持 eq、ne 过滤操作(章节 11.2.6.1.1)。
7.2. 在 $filter 表达式中支持别名(章节 11.2.6.1.3)。
7.3. 应当支持其他过滤操作(章节 11.2.6.1.1),对于任何不支持的过滤操作应返回 501 未实施(章节 9.3.1)。
7.4. 应当支持规范函数(章节 11.2.6.1.2),对于任何不支持的规范函数应返回 501 未实施(章节 9.3.1)。
7.5. 应当在扩展实体(章节 11.2.5.2.1)上支持 $filter。
- 应当在 $metadata 上发布元数据,遵循 [OData-CSDLXML](章节 11.1.2)。
- 应当支持 [OData-JSON] 格式。
- 对于与通用客户端进行最高级别的互操作性,应考虑通过 HTTPS 支持 [RFC7617] 中定义的基本认证。
- 支持 $search 系统查询选项(章节 11.2.6.6)。
- 支持 $skip 系统查询选项(章节 11.2.6.4)。
- 支持 $count 系统查询选项(章节 11.2.6.5)。
- 支持 $expand(章节 11.2.5.2)。
- 在导航和集合属性上支持 lambda 运算符 any 和 all([OData‑URL] 中的章节 5.1.1.10)。
- 在导航和集合属性上支持 /$count 段(章节 11.2.10)。
- 在单个属性上支持 $orderby asc 和 desc(章节 11.2.6.2)。
13.1.3 OData 4.0 高级一致性级别
为了符合 OData 高级符合级别,服务必须:
- 符合至少 OData 4.0 中级符合级别。
- 在 $metadata 上发布元数据,遵循 [OData-CSDLXML](章节 11.1.2)。
- 支持 [OData-JSON] 格式。
- 在导航和集合属性上支持 /$count 段(章节 11.2.10)。
- 在导航和集合属性上支持 lambda 运算符 any 和 all([OData‑URL] 中的章节 5.1.1.10)。
- 支持 $skip 系统查询选项(章节 11.2.6.4)。
- 支持 $count 系统查询选项(章节 11.2.6.5)。
- 在单个属性上支持 $orderby asc 和 desc(章节 11.2.6.2)。
- 支持 $expand(章节 11.2.5.2)。
9.1. 支持对相应导航属性返回引用。
9.2. 支持在扩展的集合属性上进行 $filter。
9.3. 支持扩展与派生类型的转换段。
9.4. 应当支持在扩展的集合属性上的 $orderby asc 和 desc。
9.5. 应当支持在扩展的集合属性上的 $count。
9.6. 应当支持在扩展的集合属性上的 ���和top和skip。
9.7. 应当支持在扩展的集合属性上的 $search。
9.8. 应当支持递归扩展的 $levels(章节 11.2.5.2.1.1)。
9.9. 可以支持在扩展属性上的 $compute。
- 支持 $search 系统查询选项(章节 11.2.6.6)。
- 支持批量请求,遵循多部分格式(章节 11.7 及其所有子章节),可以支持根据 [OData-JSON] 中定义的 JSON 批量格式进行批量请求。
- 支持 [OData‑URL] 中定义的资源路径约定。
- 应当支持异步请求(章节 11.6)。
- 应当支持增量更改追踪(章节 11.3)。
- 应当支持 [OData‑URL] 中定义的交叉连接查询。
- 可以支持 $compute 系统查询选项(章节 11.2.5.3)。
13.2 OData 4.01 服务一致性级别
OData 服务可以通过在 Core.ODataVersions 注解中包含 4.01 来报告符合 OData 4.01 规范的情况,如 [OData-VocCore] 中所定义。由于所有符合 OData 4.01 的服务必须同时完全符合 OData 4.0,因此 OData 4.01 服务不需要单独列出 4.0 作为受支持的版本。
13.2.1 OData 4.01 最低一致性级别
为了符合 OData 4.01 最低一致性级别,服务端需要:
-
符合 OData 4.0 最低一致性级别的要求。
-
采用 4.01 版本的 [OData-JSON] 格式。
-
如果支持异步操作,则在最终响应中必须返回 AsyncResult 结果头。
-
支持支持的请求头和偏好值的前缀和非前缀变体。
-
如果 $metadata 中返回 Core.SchemaVersion 注释,则如果请求中的 schemaversion 系统查询选项与之不兼容,必须拒绝该请求。
-
支持在系统查询选项中指定受支持的选项,可以包含或者不包含 $ 前缀。
-
支持不区分大小写的查询选项、操作符、以及规范函数名称。
-
在 $metadata 中以指定的小写形式返回标识符。
-
不论请求的 OData-MaxVersion 是什么,都必须支持 URL 中的 4.0 和 4.01 语法。
a. 在 URL 中支持将字符串转换为原始类型。
b. 在 URL 中支持枚举和时长字面量,可以包含或者不包含类型前缀。
c. 可以在调用参数为空的函数导入时,使用或者不使用括号。
d. 在调用没有非绑定参数的操作时,请求体可以为空或者没有内容。
e. 在调用默认命名空间中的函数和操作时,可以使用或者不使用命名空间限定。
f. 如果允许字符串字面量中包含 00 (NUL)、2F (正斜杠) 或 5C (反斜杠) 这些八位字节,则必须支持关键值和函数参数值的参数别名。
g. 应该支持参数的隐式别名。
h. 应该支持带有最大基数为 1 的导航属性的 eq/ne null 比较。
i. 应该支持 in 运算符。
j. 应该支持 divby。
k. 应该支持子字符串函数的负索引。
l. 可以支持 URL 以 Key-As-Segment 形式。
a. 必须同时支持规范的 URL 用法(在 [OData‑URL] 中有描述)或者在有效载荷中包含 URL。
m. 可以支持在常规表达式中对过滤的集合进行计数。
n. 可以支持等式和非等式的结构比较。
-
应该在 $metadata 中按照 [OData-CSDLXML] 和 [OData-CSDLJSON] (11.1.2 节) 发布元数据。
-
在唯一性作用域内(例如模式、结构类型或实体容器),不应该存在仅大小写不同的标识符。
-
应该返回 Core.ODataVersions 注释。
-
应该通过 Capabilities 词汇报告功能。
-
可以支持按注释值进行过滤。
-
可以支持 $compute 系统查询选项。
-
可以支持所有的集合使用 $search 进行过滤。
-
如果客户端没有指定 OData-MaxVersion:4.0 请求头,可以支持 4.01 的行为,包括返回 4.01 内容和有效载荷。
此外,为了被认为是一个可更新的 OData 4.01 服务,服务端需要:
- 符合 OData 4.0 可更新服务的最低一致性级别要求。
- 支持删除集合成员引用,用 key 来标识需要删除的成员 (11.4.6.2 节)。
- 应该支持对包含嵌套内容的单实体进行 PUT。
- 应该支持深度更新 (11.4.3.1 节) 和深度插入 (11.4.2.2 节)。
- 应该支持对集合值导航属性的 $ref 进行 PUT 或 DELETE。
- 可以支持对复杂/原始类型集合进行 POST。
- 可以支持对集合进行 PATCH 和 DELETE。
- 可以支持对以类型转换片段结束的集合 URL 进行 POST、PATCH 和 DELETE。
- 可以支持使用 4.01 的增量载荷格式对实体集进行 PATCH。
- 可以在数据修改请求上 支持
select和
expand。
13.2.2 OData 4.01 中级一致性级别
为了符合 OData 4.01 中级一致性级别,服务端需要:
- 符合 OData 4.01 最低一致性级别的要求。
- 符合 OData 4.0 中级一致性级别的要求。
- 支持带有最大基数为 1 的导航属性的 eq/ne null 比较。
- 支持 in 运算符。
- 支持嵌套的 $select 选项。
- 应该支持在普通表达式中对过滤的集合进行计数。
- 应该支持等式和非等式的结构比较。
- 应该支持 $compute 系统查询选项。
- 应该支持在 $select 中嵌套使用查询选项。
- 可以在 $select 和 expand 中支持嵌套的参数别名赋值。
- 可以支持使用 /$filter 路径段来过滤集合。
13.2.3 OData 4.01 高级一致性级别
为了符合 OData 4.01 高级一致性级别,服务端需要:
- 符合 OData 4.01 中级一致性级别的要求。
- 符合 OData 4.0 高级一致性级别的要求。
- 支持带有过滤/搜索集合的计数的普通表达式。
- 支持 $compute 系统查询选项。
- 支持 $select 中的嵌套选项。
5.1. 支持对选定的集合值属性进行 $filter。
5.2. 应该支持对选定的集合值属性进行 $orderby asc 和 desc。
5.3. 应该支持对选定的集合值属性进行 $count。
5.4. 应该支持对选定的集合值属性进行 top 和 skip。
5.5. 应该支持对选定的集合值属性进行 $search。
- 根据 [OData-CSDLJSON] (11.1.2 节) 的要求,在 $metadata 中发布元数据。
- 根据 [OData-JSON] 中定义的多部分格式(11.7 节和所有子节)和 JSON 批量格式,应该支持批量请求。
- 应该支持使用 /$filter 路径段来过滤集合。
- 应该支持在 $select 和 expand 中嵌套参数别名赋值。
- 可以支持在 URL 和请求有效载荷中对标识符进行不区分大小写的比较,如果找不到精确匹配,则使用与默认命名空间的不区分大小写比较相同的查找序列。
13.3 可互操作的 OData 客户端
互操作的 OData 客户端可以与至少符合 OData 4.0 的最低一致性级别和实现 OData-JSON 格式的 OData 服务一起工作。
为了达到一般的互操作性,OData 客户端需:
- 在请求中必须指定 OData-MaxVersion 标头(第 8.2.7 节)
- 在包含有效负载的任何请求中必须指定 OData-Version(第 8.1.5 节)和 Content-Type(第 8.1.1 节)
- 必须是 OData-JSON 中定义的 OData 的遵循消费者
- 必须遵循重定向(第 9.1.5 节)
- 必须正确处理 next 链接(第 11.2.6.7 节)
- 必须支持实例返回元数据中未指定的属性和导航属性(第 11.2 节)
- 如果客户端支持更新,则必须生成更新的 PATCH 请求(第 11.4.3 节)
- 在指定 OData 定义的系统查询选项时必须使用 $ 前缀
- 必须使用区分大小写的查询选项、运算符和规范函数
- 应该支持在 HTTPS 上基于RFC7617定义的基本身份验证
- 允许在响应中请求实体引用以替代先前返回的实体(第 11.2.8 节)
- 允许在增量响应中支持删除的实体、链接的实体和删除的链接实体(第 11.3 节)
- 允许支持异步响应(第 11.6 节)
- 允许在 JSON 响应中支持 metadata=minimal(参见 OData-JSON)
- 允许在 JSON 响应中支持流式传输(参见 OData-JSON)
此外,互操作的 OData 4.01 客户端:
- 必须将符合 OData 4.0 的有效负载发送到不通过 Core.ODataVersions 元数据注释(参见 OData-VocCore)广告支持 4.01 或更高版本的服务
- 在有效负载和 URL 中必须指定标识符,如果在 $metadata 中指定了它们
- 必须准备好接收任何有效的 4.01 CSDL
- 必须准备好按照请求的格式接收任何有效的 4.01 响应
- 应该使用 capabilities(参见 OData-VocCap)来确定是否支持 4.01 功能,但可以尝试语法并准备好处理 501 Not Implemented 或 400 Bad Request