5. Request/Response Semantics
CoAP 采用类似 HTTP 的请求/响应模型: 处于 "客户端" 角色的 CoAP 端点向 "服务器" 发送一个或多个 CoAP 请求, 服务器通过发送 CoAP 响应来服务这些请求. 与 HTTP 不同, 请求和响应不是在预先建立的 连接上传输, 而是通过 CoAP 消息异步交换.
5.1. Requests
CoAP 请求由要应用于 resource 的 method, resource 的 标识符, 负载和 Internet media type (如果有), 以及关于请求的可选元数据组成.
CoAP 支持 GET, POST, PUT 和 DELETE 基本 method, 它们可轻松映射到 HTTP. 它们具有与 HTTP 相同的 safe (仅检索) 和 idempotent (可多次调用且效果相同) 属性 (见 [RFC2616] Section 9.1). GET method 是 safe; 因此, 它不得对 resource 执行除检索之外的任何动作. GET, PUT 和 DELETE method 必须以 idempotent 的方式执行. POST 不是 idempotent, 因为其效果由 origin server 决定并依赖 target resource; 它通常导致创建新 resource 或更新 target resource.
请求通过将 Confirmable 或 Non-confirmable 消息的 CoAP header 中的 Code 字段设置为 Method Code 并包含请求信息来发起. 请求中使用的 method 在 Section 5.8 中详细描述.
5.2. Responses
服务器收到并解释请求后, 以 CoAP 响应响应. 该响应通过客户端生成的 token (Section 5.3) 与请求匹配; 注意, 这不同于将 Confirmable 消息与其 Acknowledgement 匹配的 Message ID.
响应通过 CoAP header 中 Code 字段设置为 Response Code 来标识. 与 HTTP Status Code 类似, CoAP Response Code 指示理解并满足请求的尝试结果. 这些 code 在 Section 5.9 中完整定义. CoAP header 的 Code 字段中可设置的 Response Code number 维护在 CoAP Response Code Registry (Section 12.1.2) 中.
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|类别| 细节 |
+-+-+-+-+-+-+-+-+
Figure 9: Structure of a Response Code
8-bit Response Code number 的高三位定义响应类别. 低五位没有分类作用; 它们为整体 类别 提供附加 细节 (Figure 9).
作为供规范和协议诊断使用的人类可读记法, 包括 Response Code 在内的 CoAP code number 记为 "c.dd", 其中 "c" 是十进制 类别, "dd" 是两位十进制 细节. 例如, "Forbidden" 写作 4.03, 表示 8-bit code value 为 十六进制 0x83 (40x20+3) 或 十进制 131 (432+3).
Response Code 有 3 个 类别:
2 - Success: 请求已成功接收, 理解并接受.
4 - Client Error: 请求包含错误语法或无法被满足.
5 - Server Error: 服务器未能满足一个显然有效的请求.
Response Code 设计为可扩展: 端点不认识的 Client Error 或 Server Error 类别 中的 Response Code, 被视为等价于该 类别 的 通用 Response Code (分别为 4.00 和 5.00). 但是, 没有表示 成功 的 通用 Response Code, 因此端点不认识的 Success 类别 中的 Response Code 只能用来判断请求成功, 而不能提供更多细节.
可能的 Response Code 在 Section 5.9 中详细描述. 响应可通过多种方式发送, 这些方式在以下小节中定义.
5.2.1. Piggybacked
最基本情况下, 响应直接承载在确认请求的 Acknowledgement 消息中 (这要求请求承载在 Confirmable 消息中). 这称为 "Piggybacked Response".
无论响应指示成功还是失败, 响应都在 Acknowledgement 消息中返回. 实际上, 响应 piggyback 在 Acknowledgement 消息上, 不需要单独的消息返回响应.
实现说明: 协议将是否 piggyback 响应 (即发送 separate response) 的决定留给服务器. 客户端必须准备接收二者之一. 从实现质量角度, 强烈期望服务器尽可能实现 piggyback, 以节省网络以及客户端和服务器上的资源.
5.2.2. Separate
并非所有情况下都能返回 piggybacked response. 例如, 服务器获取被请求 resource representation 的时间可能比它等待发回 Acknowledgement 消息的时间更长, 否则会冒着客户端反复重传请求消息的风险 (另见 Section 4.8.2 对 PROCESSING_DELAY 的讨论). 承载在 Non-confirmable 消息中的请求的响应始终单独发送 (因为没有 Acknowledgement 消息).
服务器实现这一点的一种方式是发起获取 resource representation 的尝试, 并在该过程进行时使确认定时器超时. 如果服务器预先知道不会有 piggybacked response, 也可以立即发送确认. 在两种情况下, 确认实际上都是稍后会处理该请求的承诺.
当服务器最终获得 resource representation 后, 它发送响应. 如果希望该消息不丢失, 它作为从服务器到客户端的 Confirmable 消息发送, 并由客户端以 Acknowledgement 回答, 回显服务器选择的新 Message ID. (它也可作为 Non-confirmable 消息发送; 见 Section 5.2.3.)
当服务器选择使用 separate response 时, 它以 Empty 消息形式向 Confirmable 请求发送 Acknowledgement. 一旦服务器发回 Empty Acknowledgement, 即便客户端重传另一个相同请求, 它也不得在另一个 Acknowledgement 中发回响应. 如果收到重传请求 (可能因为原 Acknowledgement 延迟), 则发送另一个 Empty Acknowledgement, 且任何响应必须作为 separate response 发送.
如果服务器随后发送 Confirmable 响应, 客户端对该响应的 Acknowledgement 必须也是 Empty 消息 (既不携带请求也不携带响应). 服务器必须在任何匹配的 Acknowledgement (静默忽略其中任何 Response Code 或负载) 或 Reset 消息上停止重传其响应.
实现说明: 注意, 由于底层数据报 transport 可能不保持顺序, 携带响应的 Confirmable 消息实际上可能在请求的 Acknowledgement 消息之前或之后到达; 为终止重传序列的目的, 这也充当确认. 还要注意, 虽然 CoAP 协议本身在此没有提出具体要求, 但从应用角度期望响应会在合理时间范围内到来. 由于没有底层传输协议可被指示运行 keep-alive 机制, 请求方可能希望设置一个与 CoAP 重传定时器无关的超时, 以应对服务器被破坏或以其他方式无法发送响应的情况.
5.2.3. Non-confirmable
如果请求消息是 Non-confirmable, 则响应应当也在 Non-confirmable 消息中返回. 但是, 端点必须准备接收对 Confirmable 请求的 Non-confirmable 响应 (其前或其后可能有 Empty Acknowledgement 消息), 或对 Non-confirmable 请求的 Confirmable 响应.
5.3. Request/Response Matching
无论响应如何发送, 它都通过客户端在请求中包含的 token, 以及对应端点的附加地址信息, 与请求匹配.
5.3.1. Token
Token 用于将响应与请求匹配. Token 值是 0 到 8 字节的序列. (注意每个消息都携带 token, 即使其长度为零.) 每个请求都携带客户端生成的 token, 服务器必须在任何产生的响应中原样回显该 token.
token 旨在作为客户端本地标识符, 用于区分 并发请求 (见 Section 5.3); 它本可称为 "请求 ID".
客户端应当以这样的方式生成 token: 对给定源/目标端点对, 当前正在使用的 token 是唯一的. (注意, 如果客户端实现每次使用不同端点, 例如不同源端口号, 则可对任何请求使用相同 token.) 当对某目标没有其他 token 正在使用时, 或每个目标串行发出请求并接收 piggybacked response 时, 空 Token 值是合适的. 但有多种实现策略可满足此要求.
未使用 Transport Layer Security (Section 9) 发送请求的客户端应当使用非平凡的随机化 token, 以防御响应欺骗 (Section 11.4). token 的这种保护性用途是其最大允许 8 字节的原因. Token 中实际使用的随机部分大小取决于客户端的安全需求以及响应欺骗的威胁级别. 连接到普通 Internet 的客户端应当使用至少 32 bits 随机性, 并记住未直接连接到 Internet 不一定足以防止欺骗. (注意, Message ID 提供的保护很少, 因为它通常顺序分配, 即可猜测, 并且可通过 伪造 separate response 绕过.) 希望优化 Token 长度的客户端还可检测正在发生的攻击级别 (例如统计传入消息中最近的 Token 不匹配), 并适当提高 Token 长度. [RFC4086] 讨论了安全所需的随机性.
收到非自己生成 token 的端点必须将该 token 视为 opaque, 不对其内容或结构作任何假设.
5.3.2. Request/Response Matching Rules
将响应与请求匹配的精确规则如下:
-
响应的源端点必须与原始请求的目标端点相同.
-
在 piggybacked response 中, Confirmable 请求与 Acknowledgement 的 Message ID 必须匹配, 且响应与原始请求的 token 必须匹配. 在 separate response 中, 只要求响应与原始请求的 token 必须匹配.
如果携带响应的消息是 意外 (客户端没有等待来自标识端点, 发往所寻址端点, 和/或带有给定 token 的响应), 则拒绝该响应 (Sections 4.2 和 4.3).
实现说明: 收到 CON 消息中 响应的客户端可能希望在发送 ACK 后立即清理消息状态. 如果该 ACK 丢失且服务器重传 CON, 客户端可能不再有任何状态来关联该响应, 使该重传成为 意外 消息; 客户端很可能发送 Reset 消息, 以免再接收更多重传. 这种行为是正常的, 并不表示错误. (未激进优化状态内存使用的客户端仍会有消息状态, 可将第二个 CON 标识为重传. 实际期望从服务器收到更多消息的 客户端 [OBSERVE] 无论如何都必须保留状态.)
5.4. Options
请求和响应都可包含一个或多个选项的列表. 例如, 请求中的 URI 通过多个选项传输, HTTP 中会由 HTTP header 携带的元数据也作为选项提供.
CoAP 定义单一选项集, 用于请求和响应:
o Content-Format
o ETag
o Location-Path
o Location-Query
o Max-Age
o Proxy-Uri
o Proxy-Scheme
o Uri-Host
o Uri-Path
o Uri-Port
o Uri-Query
o Accept
o If-Match
o If-None-Match
o Size1
这些选项的语义及其属性在 Section 5.10 中详细定义.
并非所有选项都定义为可与所有 method 和 Response Code 一起使用. method 和 Response Code 的可能选项分别在 Sections 5.8 和 5.9 中定义. 如果某选项未针对某 Method 或 Response Code 定义, 发送方不得包含它, 接收方必须将其视为 无法识别的选项.
5.4.1. Critical/Elective
选项分为两类: "critical" 或 "elective". 二者差异在于端点如何处理不认识的选项:
o 接收时, "elective" 类别 的 无法识别的选项必须被静默忽略.
o Confirmable 请求中出现的 "critical" 类别 无法识别的选项必须导致返回 4.02 (Bad Option) 响应. 该响应应当包含描述 无法识别的选项的 诊断负载 (见 Section 5.5.2).
o Confirmable 响应中出现的, 或 piggyback 在 Acknowledgement 中的 "critical" 类别 无法识别的选项必须导致响应被拒绝 (Section 4.2).
o Non-confirmable 消息中出现的 "critical" 类别 无法识别的选项必须导致消息被拒绝 (Section 4.3).
注意, 无论 critical 还是 elective, 选项都从不是 "mandatory" (它总是 optional): 这些规则的定义是为了让实现能停止处理其不理解或未实现的选项.
Critical/elective 规则适用于 非代理 端点. 代理基于 Section 5.7 中定义的 Unsafe/Safe-to-Forward 类别 处理选项.
5.4.2. Proxy Unsafe or Safe-to-Forward and NoCacheKey
除了标记为 critical 或 elective, 选项还根据代理在不认识该选项时应如何处理来分类. 为此, 选项可被认为 Unsafe to forward (UnSafe is set) 或 Safe-to-Forward (UnSafe is clear).
此外, 对标记为 Safe-to-Forward 的选项, 选项编号指示它是否旨在成为请求中 Cache-Key (Section 5.6) 的一部分. 如果某些 NoCacheKey bit 为 0, 它就是; 如果所有 NoCacheKey bit 都为 1, 它就不是 (见 Section 5.4.6).
注意: Cache-Key 指示只与不将给定选项实现为请求选项, 而只依赖 Unsafe/Safe-to-Forward 指示的代理相关. 例如, 对 ETag 来说, 实际使用请求选项作为 Cache-Key 的一部分效率极低, 但如果代理未实现 ETag, 这是它能做的最佳选择, 因为响应会根据该请求选项是否存在而不同. 更有用且实现了 ETag 请求选项的 代理不会将 ETag 用作 Cache-Key 的一部分.
NoCacheKey 使用三个位指示, 因而只有八个 codepoint 中的一个被限定为 NoCacheKey, 留下八个 codepoint 中的七个给看起来更可能的情况.
代理关于这些 类别 的行为在 Section 5.7 中定义.
5.4.3. Length
选项值被定义为具有特定长度, 通常以上下界形式给出. 如果请求中 选项值的长度超出定义范围, 该选项必须被视为 无法识别的选项 (见 Section 5.4.1).
5.4.4. Default Values
选项可定义为具有默认值. 如果选项的值意图为该默认值, 则该选项不应包含在消息中. 如果该选项不存在, 必须假定默认值.
在 critical 选项具有默认值的地方, 该值的选择方式使得消息中缺少该选项时, 不知道该 critical 选项的实现以及将这种缺失解释为该选项默认值存在的实现都能正确处理.
5.4.5. Repeatable Options
某些选项的定义指定这些选项是 repeatable. repeatable 选项可以在 消息中包含一次或多次. 非 repeatable 选项不得在 消息中包含超过一次.
如果消息包含某选项的出现次数多于该选项定义所允许的次数, 消息中随后出现的每个超额选项出现 必须被视为 无法识别的选项 (见 Section 5.4.1).
5.4.6. Option Numbers
Option 由选项编号标识, 该 number 还提供一些附加语义信息, 例如 奇数 表示 critical 选项, 偶数 表示 elective 选项. 注意, 这不只是约定, 而是协议特性: 选项是 elective 还是 critical 完全由其选项编号是偶数还是奇数决定.
更一般地说, Option number 使用 位掩码 构造, 用来指示选项是 Critical 还是 Elective, Unsafe 还是 Safe-to-Forward, 并在 Safe-to-Forward 情况下提供 Cache-Key 指示, 如下图所示. 在以下文字中, 位掩码 表示为单个 byte, 应用于 unsigned integer 表示中选项编号的最低有效字节. 当 bit 7 (最低有效位) 为 1 时, 选项为 Critical (为 0 时同理为 Elective). 当 bit 6 为 1 时, 选项为 Unsafe (为 0 时同理为 Safe-to-Forward). 当 bit 6 为 0, 即选项不是 Unsafe 时, 当且仅当 bits 3-5 全部设置为 1 时, 它不是 Cache-Key (NoCacheKey); 所有其他 bit 组合 表示它确实是 Cache-Key. 这些选项 类别 在下一节解释.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| | NoCacheKey| U | C |
+---+---+---+---+---+---+---+---+
Figure 10: Option Number Mask (Least Significant Byte)
端点可使用 Figure 11 中 C code 的等价形式, 从选项编号"onum" 推导其特性.
Critical = (onum & 1); UnSafe = (onum & 2); NoCacheKey = ((onum & 0x1e) == 0x1c);
Figure 11: Determining Characteristics from an Option Number
本文档定义的选项的 选项编号列在 "CoAP Option Numbers" registry (Section 12.2) 中.
5.5. Payloads and Representations
请求和响应都可包含负载, 分别取决于 Method 或 Response Code. 如果某 Method 或 Response Code 未定义为具有负载, 发送方不得包含负载, 接收方必须忽略它.
5.5.1. Representation
请求或指示成功 的响应的负载通常是 resource 的 representation ("resource representation") 或所请求动作的结果 ("action result"). 其格式由 Content-Format Option 给出的 Internet media type 和 content coding 指定. 如果没有该选项, 不假定默认值, 格式需要由应用推断 (例如根据应用上下文). 负载 "sniffing" 应当仅在没有给出 content type 时尝试.
实现说明: 从实现质量角度, 强烈期望只要可能就随 resource representation 提供 Content-Format 指示. 这不是 "应当" 级别要求, 仅因为它不是协议要求, 并且也很难准确说明在哪些情况下可以违反这种期望.
对于指示客户端或服务器错误的响应, 只有在给出 Content-Format Option 时, 负载才被视为所请求动作结果的 representation. 没有该选项时, 负载是 Diagnostic Payload (Section 5.5.2).
5.5.2. Diagnostic Payload
如果未给出 Content-Format 选项, 指示客户端或服务器错误的响应的负载是简短的人类可读 诊断消息, 用于解释错误情况. 该 诊断消息必须使用 UTF-8 [RFC3629] 编码, 更具体地说使用 Net-Unicode form [RFC5198].
该消息类似 HTTP status line 上的 Reason-Phrase. 它不是面向最终用户, 而是面向调试期间需要在当前英文规范上下文中解释它的软件工程师; 因此不需要也不提供 语言标记 机制. 与 HTTP 中的常规情况相反, 如果除 Response Code 外没有附加信息, 负载应当为空.
5.5.3. Selected Representation
并非所有响应都携带提供请求所寻址 resource representation 的负载. 但是, 有时即使 representation 实际上未封装在响应中, 也需要能够相对于响应指称这样的 representation.
我们使用术语 "selected representation" 指 target resource 的当前 representation, 即如果对应请求使用 GET method 且排除任何 conditional 请求选项 (Section 5.10.8), 在成功响应中本会被选择的 representation.
某些响应选项提供关于 selected representation 的元数据, 这可能不同于对某些 state-changing method 的响应中包含的 representation. 在本规范定义的响应选项中, 只有 ETag 响应选项 (Section 5.10.6) 被定义为关于 selected representation 的元数据.
5.5.4. Content Negotiation
服务器可能能够以多种 representation format 之一提供 resource 的 representation. 如果客户端没有提供更多信息, 服务器将以其偏好的 format 提供 representation.
通过在请求中使用 Accept Option (Section 5.10.4), 客户端可指示它偏好接收的 Content-Format.
5.6. Caching
CoAP 端点可以缓存响应, 以减少未来等价请求的响应时间 和网络带宽 消耗.
CoAP 中缓存的目标是复用先前响应消息来满足当前请求. 在某些情况下, 已存储响应可无需 网络请求即可复用, 从而降低延迟和 网络往返; 为此使用 "新鲜度" 机制 (见 Section 5.6.1). 即便需要新请求, 也常可复用先前响应的负载来满足请求, 从而降低网络带宽使用量; 为此使用 "验证" 机制 (见 Section 5.6.2).
与 HTTP 不同, CoAP 响应的 可缓存性 不取决于请求 method, 而取决于 Response Code. 每个 Response Code 的 可缓存性 随 Section 5.9 中的 Response Code 定义给出. 指示成功 且端点不认识的 Response Code 不得被缓存.
对于提出的请求, CoAP 端点不得使用 已存储响应, 除非:
o 提出的请求 method 与用于获取 已存储响应的 method 匹配.
o 提出的请求中的所有选项与用于获取 已存储响应的请求中的选项均匹配 (这包括请求 URI), 但以下请求选项无需匹配: 标记为 NoCacheKey 的选项 (Section 5.4), 或被 Cache 识别并相对于其指定缓存行为完全解释的选项 (如 Section 5.10.6 中描述的 ETag 请求选项; 另见 Section 5.4.2).
o 已存储响应要么新鲜, 要么按下文定义成功验证.
用于匹配缓存条目 的请求选项集合也统称为 "Cache-Key". 对 coap 和 coaps 以外的 URI scheme, 构成请求 URI 的那些选项的匹配可按 URI scheme 特定规则执行.
5.6.1. Freshness Model
当响应在缓存中为 "新鲜" 时, 它可用于满足后续请求, 而无需联系 origin server, 从而提升效率.
确定新鲜度的机制是 origin server 使用 Max-Age Option (见 Section 5.10.5) 提供未来的显式 expiration time. Max-Age Option 指示当响应的 age 大于指定秒数后, 该响应应视为不再新鲜.
Max-Age Option 默认值为 60. 因此, 如果可缓存 响应中不存在该选项, 则响应在其 age 大于 60 seconds 后被视为不再新鲜. 如果 origin server 希望防止缓存, 它必须显式包含值为 zero seconds 的 Max-Age Option.
如果客户端有 新鲜的已存储响应并发出一个与该 已存储响应的请求匹配的新请求, 新响应会使旧响应失效.
5.6.2. Validation Model
当端点对 GET 请求有一个或多个已存储响应, 但不能使用其中任何一个 (例如因为它们不新鲜) 时, 它可在 GET 请求中使用 ETag Option (Section 5.10.6), 给 origin server 机会选择一个要使用的 已存储响应并更新其 新鲜度. 此过程称为 "验证" 或 "重新验证" 已存储响应.
发送此类请求时, 端点应当添加 ETag Option, 指定每个适用的已存储响应的 entity-tag.
2.03 (Valid) 响应指示响应的 ETag Option 中给出的 entity-tag 所标识的已存储响应, 可在按 Section 5.9.1.3 描述更新后复用.
任何其他 Response Code 都表示请求中提名的 已存储响应均不适用. 相反, 响应应当用于满足请求, 并且可以替换已存储响应.
5.7. Proxying
代理是可由 CoAP 客户端指派代表其执行请求的 CoAP 端点. 例如, 当请求原本无法发出时, 或为了从缓存服务响应以减少响应时间, 网络带宽或 能耗时, 这可能有用.
在 Constrained RESTful Environment 的整体架构中, 代理可服务于相当不同的目的. 代理可由客户端显式选择, 我们称此角色为 "forward-proxy". 代理也可被插入以代表 origin server, 我们称此角色为 "reverse-proxy". 与此区分正交的是, 代理可从 CoAP 请求映射到 CoAP 请求 (CoAP-to-CoAP 代理), 或从/向不同协议转换 ("cross-proxy"). 这些术语的完整定义见 Section 1.2.
注意: 本规范中的术语选择为与更广泛 Web 应用环境 中使用的术语在文化上兼容, 但不必在每个细节上匹配 (那些细节甚至可能与 Constrained RESTful Environment 无关). 不应对术语组成部分 (如 "forward", "reverse" 或 "cross") 赋予过多语义.
HTTP 代理除了作为 HTTP 代理外, 通常还提供 传输协议代理功能 ("CONNECT"), 以支持通过代理的 端到端传输层安全. 本规范没有为 CoAP-to-CoAP 代理定义这种功能, 因为在 Constrained RESTful Environment 中转发 UDP 数据包不太可能有很大价值. cross-proxy情况另见 Section 10.2.7.
当客户端使用代理发出将使用 安全 URI scheme (例如 "coaps" 或 "https") 的请求时, 面向代理的 请求应当使用 DTLS 发送, 除非客户端与 代理之间这一段使用了等价的 下层安全.
5.7.1. Proxy Operation
代理通常需要一种方式, 基于它从客户端收到的请求, 为它向目标发出的请求确定潜在请求 parameter. 对 forward-proxy, 这种方式已完全规定; 对 reverse-proxy, 它可能取决于具体配置. 特别是, reverse-proxy 的 客户端通常不指示目标的 locator, 因而需要 reverse-proxy 中某种形式的 命名空间转换. 但是, 代理操作的一些方面对所有形式都相同.
如果代理不使用缓存, 它只需将转换后的请求转发到确定的目标. 否则, 如果它使用缓存但没有与转换后请求匹配且被认为新鲜的 已存储响应, 它需要按 Section 5.6 刷新其缓存. 对代理识别的请求选项, 它知道该选项是否旨在作为查找 缓存值 所用 键的一部分. 例如, 由于不同 Uri-Path 值的请求寻址不同 resource, Uri-Path 值始终是 Cache-Key 的一部分, 而 Token 值则从不是 Cache-Key 的一部分. 对代理不认识但在选项编号中标记为 Safe-to-Forward 的选项, 该选项还指示是否应包含在 Cache-Key 中 (NoCacheKey 未全部设置) 或不包含 (NoCacheKey 全部设置). (unrecognized 且标记为 Unsafe 的选项导致 4.02 Bad Option.)
如果面向目标的 请求超时, 必须返回 5.04 (Gateway Timeout) 响应. 如果面向目标的 请求返回了代理无法处理的响应 (例如因 无法识别的 critical 选项或 消息格式错误), 必须返回 5.02 (Bad Gateway) 响应. 否则, 代理将 响应返回给客户端.
如果响应从 缓存生成, 生成的 (或隐含的) Max-Age Option 不得在考虑 resource representation 在缓存中花费的时间后, 延长服务器最初设置的 max-age. 例如, 代理可对每个响应使用以下公式调整 Max-Age Option:
代理-max-age = original-max-age - 缓存-age
例如, 如果对一个 proxied resource 发出请求, 该 resource 20 seconds 前刷新且原始 Max-Age 为 60 seconds, 则该 resource 当前的 proxied max-age 为 40 seconds. 考虑从 origin server 经过来的潜在 网络延迟, 代理应对提供的 max-age 值保持保守.
代理请求中存在的所有选项必须在代理处处理. 请求中代理不认识的 Unsafe 选项必须导致代理返回 4.02 (Bad Option) 响应. CoAP-to-CoAP 代理必须将其不认识的所有 Safe-to-Forward 选项转发给 origin server. 类似地, 响应中 CoAP-to-CoAP 代理服务器不认识的 Unsafe 选项必须导致 5.02 (Bad Gateway) 响应. 同样, 不认识的 Safe-to-Forward 选项必须被转发.
CoAP 与 HTTP 之间 cross-protocol proxying 的额外注意事项在 Section 10 中讨论.
5.7.2. Forward-Proxies
CoAP 区分向 origin server 发出的请求 (或仿佛向其发出) 与通过 forward-proxy 发出的请求. 发往 forward-proxy 的 CoAP 请求作为普通 Confirmable 或 Non-confirmable 请求发往 forward-proxy 端点, 但它们以不同方式指定请求 URI: 代理请求中的请求 URI 作为字符串在 Proxy-Uri Option 中指定 (见 Section 5.10.2), 而发往 origin server 的 请求中的请求 URI 被拆分为 Uri-Host, Uri-Port, Uri-Path 和 Uri-Query Option (见 Section 5.10.1). 或者, 代理请求中的 URI 可由 Proxy-Scheme 选项和前述拆分选项组装.
当向端点发出代理请求, 而该端点不愿或不能为该请求 URI 充当代理时, 它必须返回 5.05 (Proxying Not Supported) 响应. 如果 authority (host 和 port) 被识别为标识代理端点自身 (见 Section 5.10.2), 则该请求必须被视为 local (non-proxied) 请求.
除非代理配置为将代理请求转发给另一个代理, 否则它必须按如下方式转换请求: 请求 URI 的 scheme 定义 出站协议 及其细节 (例如, "coap" scheme 使用 UDP 上的 CoAP, "coaps" scheme 使用 DTLS 上的 CoAP). 对 CoAP-to-CoAP 代理, origin server 的 IP 地址和 port 由请求 URI 的 authority component 确定, 请求 URI 被解码并拆分为 Uri-Host, Uri-Port, Uri-Path 和 Uri-Query Option. 这会消耗 Proxy-Uri 或 Proxy-Scheme 选项, 因而它不会被转发给 origin server.
5.7.3. Reverse-Proxies
Reverse-proxy不使用 Proxy-Uri 或 Proxy-Scheme 选项, 而需要根据请求中的信息和其配置中的信息确定请求的目标 (next hop). 例如, reverse-proxy 可将各种 resource 提供得仿佛它们是自己的 resource, 这些 resource 的存在是通过 resource discovery 获知的. reverse-proxy 可自由为标识这些 resource 的 URI 构建 namespace. reverse-proxy 也可构建 namespace, 使客户端对 请求去向有更多控制, 例如把 host 标识符 和端口号嵌入所提供 resource 的 URI path 中.
处理响应时, reverse-proxy 必须小心, 避免来自不同源的 ETag 选项值在提供给客户端的同一 resource 上混淆. 在许多情况下, ETag 可原样转发. 如果 reverse-proxy 提供的 resource 到其各 origin server 提供的 resource 的映射不是唯一的, reverse-proxy 可能需要生成新的 ETag, 同时确保正确保留该选项的语义.
5.8. Method Definitions
本节定义每个 method 及其行为. 带有 无法识别或不支持的 Method Code 的请求必须生成 4.05 (Method Not Allowed) piggybacked response.
5.8.1. GET
GET method 检索当前对应于请求 URI 所标识 resource 的信息 representation. 如果请求包含 Accept Option, 它指示响应的首选 Content-Format. 如果请求包含 ETag Option, GET method 请求验证 ETag, 并且只有验证失败时才传输 representation. 成功时, 响应中应当存在 2.05 (Content) 或 2.03 (Valid) Response Code.
GET method 是 safe 且 idempotent.
5.8.2. POST
POST method 请求处理请求中封装的 representation. POST method 执行的实际功能由 origin server 决定并依赖 target resource. 它通常导致创建新 resource 或更新 target resource.
如果服务器上创建了 resource, 服务器返回的响应应当具有 2.01 (Created) Response Code, 并应当在一个或多个 Location-Path 和/或 Location-Query Option 序列中包含新 resource 的 URI (Section 5.10.7). 如果 POST 成功但未导致服务器上创建新 resource, 响应应当具有 2.04 (Changed) Response Code. 如果 POST 成功并导致 target resource 被删除, 响应应当具有 2.02 (Deleted) Response Code. POST 既不是 safe, 也不是 idempotent.
5.8.3. PUT
PUT method 请求使用封装的 representation 更新或创建请求 URI 所标识的 resource. representation format 由 Content-Format Option 中给出的 media type 和 content coding 指定, 如果提供该选项.
如果请求 URI 处存在 resource, 封装的 representation 应当被视为该 resource 的修改版本, 并应当返回 2.04 (Changed) Response Code. 如果不存在 resource, 服务器可以使用该 URI 创建新 resource, 从而产生 2.01 (Created) Response Code. 如果 resource 无法创建或修改, 应当发送适当的 error Response Code.
可通过在请求中包含 If-Match (见 Section 5.10.8.1) 或 If-None-Match (见 Section 5.10.8.2) 选项, 对 PUT 施加进一步限制.
PUT 不是 safe, 但为 idempotent.
5.8.4. DELETE
DELETE method 请求删除请求 URI 所标识的 resource. 成功时或在请求之前 resource 本就不存在时, 应当使用 2.02 (Deleted) Response Code.
DELETE 不是 safe, 但为 idempotent.
5.9. Response Code Definitions
下面描述每个 Response Code, 包括响应中所需的任何选项. 在适当位置, 某些 code 会相对于 HTTP [RFC2616] 中相关 Response Code 加以说明; 这并不意味着任何此类关系会修改 Section 10 中规定的 HTTP mapping.
5.9.1. Success 2.xx
此类 Response Code 指示客户端请求已成功接收, 理解并接受.
5.9.1.1. 2.01 Created
类似 HTTP 201 "Created", 但仅用于对 POST 和 PUT 请求的响应. 响应随附返回的负载 (如果有) 是 action result 的 representation.
如果响应包含一个或多个 Location-Path 和/或 Location-Query Option, 这些选项的值指定 resource 被创建的位置. 否则, resource 在请求 URI 处创建. 接收此响应的 缓存必须将为已创建 resource 存储的任何响应标记为 非新鲜.
此响应不可缓存.
5.9.1.2. 2.02 Deleted
此 Response Code 类似 HTTP 204 "No Content", 但仅用于响应导致 resource 不再可用的请求, 如 DELETE 以及某些情况下的 POST. 响应随附返回的负载 (如果有) 是 action result 的 representation.
此响应不可缓存. 但是, 缓存必须将为已删除 resource 存储的任何响应标记为 非新鲜.
5.9.1.3. 2.03 Valid
此 Response Code 与 HTTP 304 "Not Modified" 相关, 但仅用于指示由所包含 ETag Option 标识的 entity-tag 所标识的响应有效. 因此, 响应必须包含 ETag Option, 并且不得包含负载.
当识别并处理 ETag 响应选项的 缓存收到 2.03 (Valid) 响应时, 它必须使用响应中包含的 Max-Age Option 的值 (显式值或隐式默认值; 另见 Section 5.6.2) 更新 已存储响应. 对响应中存在的每种 Safe-to-Forward 选项类型, 已存储响应中存在的该类型选项集合 (可能为空) 必须替换为所收到响应中该类型选项的集合. (Unsafe 选项可触发选项特定处理, 如该选项所定义.)
5.9.1.4. 2.04 Changed
此 Response Code 类似 HTTP 204 "No Content", 但仅用于响应 POST 和 PUT 请求. 响应随附返回的负载 (如果有) 是 action result 的 representation.
此响应不可缓存. 但是, 缓存必须将为已更改 resource 存储的任何响应标记为 非新鲜.
5.9.1.5. 2.05 Content
此 Response Code 类似 HTTP 200 "OK", 但仅用于响应 GET 请求.
响应随附返回的负载是 target resource 的 representation.
此响应可缓存: 缓存可使用 Max-Age Option 确定新鲜度 (见 Section 5.6.1), 并使用 ETag Option (如果存在) 进行验证 (见 Section 5.6.2).
5.9.2. Client Error 4.xx
此类 Response Code 用于客户端似乎出错的情况. 这些 Response Code 适用于任何请求 method.
服务器应当在 Section 5.5.2 详述的条件下包含 诊断负载.
此类响应可缓存: 缓存可使用 Max-Age Option 确定新鲜度 (见 Section 5.6.1). 它们不能验证.
5.9.2.1. 4.00 Bad Request
此 Response Code 类似 HTTP 400 "Bad Request".
5.9.2.2. 4.01 Unauthorized
客户端未被授权执行所请求的动作. 客户端不应在未先改善其对服务器的 认证状态 前重复该请求. 可用于此的具体机制超出本文档范围; 另见 Section 9.
5.9.2.3. 4.02 Bad Option
由于一个或多个 无法识别或格式错误的 选项, 服务器无法理解请求. 客户端不应在不修改的情况下重复该请求.
5.9.2.4. 4.03 Forbidden
此 Response Code 类似 HTTP 403 "Forbidden".
5.9.2.5. 4.04 Not Found
此 Response Code 类似 HTTP 404 "Not Found".
5.9.2.6. 4.05 Method Not Allowed
此 Response Code 类似 HTTP 405 "Method Not Allowed", 但没有与 "Allow" header field 对应的并行项.
5.9.2.7. 4.06 Not Acceptable
此 Response Code 类似 HTTP 406 "Not Acceptable", 但没有response entity.
5.9.2.8. 4.12 Precondition Failed
此 Response Code 类似 HTTP 412 "Precondition Failed".
5.9.2.9. 4.13 Request Entity Too Large
此 Response Code 类似 HTTP 413 "Request Entity Too Large".
响应应当包含 Size1 Option (Section 5.10.9), 用于指示服务器能够且愿意处理的请求实体最大大小, 除非服务器无法提供此信息.
5.9.2.10. 4.15 Unsupported Content-Format
此 Response Code 类似 HTTP 415 "Unsupported Media Type".
5.9.3. Server Error 5.xx
此类 Response Code 指示服务器意识到自己出错或无法执行请求的情况. 这些 Response Code 适用于任何请求 method.
服务器应当在 Section 5.5.2 详述的条件下包含 诊断负载.
此类响应可缓存: 缓存可使用 Max-Age Option 确定新鲜度 (见 Section 5.6.1). 它们不能验证.
5.9.3.1. 5.00 Internal Server Error
此 Response Code 类似 HTTP 500 "Internal Server Error".
5.9.3.2. 5.01 Not Implemented
此 Response Code 类似 HTTP 501 "Not Implemented".
5.9.3.3. 5.02 Bad Gateway
此 Response Code 类似 HTTP 502 "Bad Gateway".
5.9.3.4. 5.03 Service Unavailable
此 Response Code 类似 HTTP 503 "Service Unavailable", 但使用 Max-Age Option 代替 "Retry-After" header field 来指示经过多少秒后重试.
5.9.3.5. 5.04 Gateway Timeout
此 Response Code 类似 HTTP 504 "Gateway Timeout".
5.9.3.6. 5.05 Proxying Not Supported
服务器无法或不愿为 Proxy-Uri Option 中指定的 URI 或使用 Proxy-Scheme (见 Section 5.10.2) 充当 forward-proxy.
5.10. Option Definitions
单个 CoAP 选项汇总在 Table 4 中, 并在本节各小节解释.
在此表中, C, U 和 N 列分别指示 Critical, UnSafe 和 NoCacheKey 属性. 由于 NoCacheKey 只对 Safe-to-Forward (未标记 Unsafe) 的选项有意义, UnSafe 选项的该列填入 dash.
+-----+---+---+---+---+----------------+--------+--------+----------+ | No. | C | U | N | R | Name | Format | Length | Default | +-----+---+---+---+---+----------------+--------+--------+----------+ | 1 | x | | | x | If-Match | opaque | 0-8 | (none) | | 3 | x | x | - | | Uri-Host | string | 1-255 | (see | | | | | | | | | | below) | | 4 | | | | x | ETag | opaque | 1-8 | (none) | | 5 | x | | | | If-None-Match | empty | 0 | (none) | | 7 | x | x | - | | Uri-Port | uint | 0-2 | (see | | | | | | | | | | below) | | 8 | | | | x | Location-Path | string | 0-255 | (none) | | 11 | x | x | - | x | Uri-Path | string | 0-255 | (none) | | 12 | | | | | Content-Format | uint | 0-2 | (none) | | 14 | | x | - | | Max-Age | uint | 0-4 | 60 | | 15 | x | x | - | x | Uri-Query | string | 0-255 | (none) | | 17 | x | | | | Accept | uint | 0-2 | (none) | | 20 | | | | x | Location-Query | string | 0-255 | (none) | | 35 | x | x | - | | Proxy-Uri | string | 1-1034 | (none) | | 39 | x | x | - | | Proxy-Scheme | string | 1-255 | (none) | | 60 | | | x | | Size1 | uint | 0-4 | (none) | +-----+---+---+---+---+----------------+--------+--------+----------+
C=Critical, U=Unsafe, N=NoCacheKey, R=Repeatable
Table 4: Options
5.10.1. Uri-Host, Uri-Port, Uri-Path, and Uri-Query
Uri-Host, Uri-Port, Uri-Path 和 Uri-Query Option 用于指定发往 CoAP origin server 的 请求的 target resource. 这些选项以 选项值中不可见 percent-encoding 的方式编码请求 URI 的不同 component, 并使完整 URI 可在任何相关端点重构. CoAP URI 的语法在 Section 6 中定义.
将 URI 解析为选项的步骤在 Section 6.4 中定义. 这些步骤会使请求中包含零个或多个 Uri-Host, Uri-Port, Uri-Path 和 Uri-Query Option, 每个选项保存以下值:
o Uri-Host Option 指定被请求 resource 的 Internet host.
o Uri-Port Option 指定 resource 的 transport-layer 端口号.
o 每个 Uri-Path Option 指定到 resource 的 绝对路径的一个 segment.
o 每个 Uri-Query Option 指定一个参数化 resource 的 argument.
注意: Fragment ([RFC3986], Section 3.5) 不是请求 URI 的一部分, 因而不会在 CoAP 请求中传输.
Uri-Host Option 的默认值是表示请求消息目标 IP 地址的 IP literal. 同样, Uri-Port Option 的默认值是 目标 UDP port. Uri-Host 和 Uri-Port Option 的默认值足以用于发往大多数服务器的 请求. 显式 Uri-Host 和 Uri-Port Option 通常在端点托管多个 virtual 服务器时使用.
Uri-Path 和 Uri-Query Option 可包含任何 字符序列. 不执行 percent-encoding. Uri-Path Option 的值不得为 "." 或 ".." (因为请求 URI 必须在解析为选项之前先解析完成).
从选项构造请求 URI 的步骤在 Section 6.5 中定义. 注意, 实现不一定必须构造 URI; 它可以只检查单个选项来查找 target resource.
示例见 Appendix B.
5.10.2. Proxy-Uri and Proxy-Scheme
Proxy-Uri Option 用于向 forward-proxy 发出请求 (见 Section 5.7). forward-proxy被请求转发该请求, 或从有效缓存服务它并返回响应.
选项值是 absolute-URI ([RFC3986], Section 4.3).
注意, forward-proxy可以将 请求继续转发给另一个代理, 或直接转发给 absolute-URI 指定的服务器. 为避免请求 loop, 代理必须能识别其所有服务器 name, 包括任何 alias, 本地变体和 numeric IP 地址.
收到带 Proxy-Uri Option 的请求且无法或不愿为该请求充当 forward-proxy 的 端点必须导致返回 5.05 (Proxying Not Supported) 响应.
Proxy-Uri Option 必须优先于任何 Uri-Host, Uri-Port, Uri-Path 或 Uri-Query 选项 (这些选项中每一个都不得包含在带 Proxy-Uri Option 的请求中).
作为简化许多代理客户端的特殊情况, absolute-URI 可由 Uri-* 选项构造. 当存在 Proxy-Scheme Option 时, absolute-URI 按如下方式构造: 按 Section 6.5 定义从 Uri-* 选项构造 CoAP URI. 在所得 URI 中, 将初始 scheme 直到但不包括后续 colon 的部分替换为 Proxy-Scheme Option 的内容. 注意, 这种情况只适用于所需 URI 除 scheme component 外的 component 确实可用 Uri-* 选项表达的情况; 例如, 要表示 authority 中带 userinfo component 的 URI, 只能使用 Proxy-Uri.
5.10.3. Content-Format
Content-Format Option 指示消息负载的 representation format. representation format 作为数字 Content-Format 标识符 给出, 该标识符定义在 "CoAP Content-Formats" registry (Section 12.3) 中. 如果缺少该选项, 不假定默认值, 即任何 representation 消息负载的 representation format 都是不确定的 (Section 5.5).
5.10.4. Accept
CoAP Accept 选项可用于指示客户端可接受哪个 Content-Format. representation format 作为数字 Content-Format 标识符 给出, 该标识符定义在 "CoAP Content-Formats" registry (Section 12.3) 中. 如果未给出 Accept 选项, 客户端不表达偏好 (因此不假定默认值). 客户端偏好服务器返回的 representation 采用所指示 Content-Format. 如果可用, 服务器返回该首选 Content-Format. 如果无法返回首选 Content-Format, 则必须发送 4.06 "Not Acceptable" 作为响应, 除非另一个 error code 对此响应具有优先级.
5.10.5. Max-Age
Max-Age Option 指示响应在被视为 非新鲜之前可缓存的最长时间 (见 Section 5.6.1).
选项值是 0 到 2**32-1 (含) 之间的整数秒数 (约 136.1 years). 如果响应中缺少该选项, 则假定默认值为 60 seconds.
该值意图在传输时为当前值. 提供对 Max-Age 值有严格容差 resource 的服务器应当在每次重传前更新该值. (另见 Section 5.7.1.)
5.10.6. ETag
entity-tag 旨在作为 resource-local 标识符, 用于区分同一 resource 随时间变化的不同 representation. 它由提供 resource 的服务器生成, 服务器可用任意多种方式生成它, 包括 version, checksum, hash 或 time. 收到 entity-tag 的端点必须将其视为 opaque, 不对其内容或结构作任何假设. (鼓励生成 entity-tag 的端点使用尽可能紧凑的 representation, 尤其考虑可能希望存储多个 ETag value 的客户端和 intermediary.)
5.10.6.1. ETag as a Response Option
响应中的 ETag Option 提供 "tagged representation" 的 entity-tag 当前值 (即请求处理之后的值). 如果不存在 Location-* 选项, tagged representation 是 target resource 的 selected representation (Section 5.5.3). 如果存在一个或多个 Location-* 选项, 从而指示了 location URI (Section 5.10.7), tagged representation 是对该 location URI 发出 GET 请求时会检索到的 representation.
ETag 响应选项可包含在任何有 tagged representation 的响应中 (例如在 4.04 或 4.00 响应中没有意义). ETag Option 不得在响应中出现超过一次.
ETag Option 没有默认值; 如果它不在响应中出现, 服务器不对 tagged representation 的 entity-tag 作任何陈述.
5.10.6.2. ETag as a Request Option
在 GET 请求中, 已从 resource 获得一个或多个 representation 并随之获得 ETag 响应选项的端点, 可为这些 已存储响应中的一个或多个指定一个 ETag Option 实例.
如果给定 ETag 之一是当前 representation 的 entity-tag, 即有效, 服务器可发出 2.03 Valid 响应 (Section 5.9.1.3) 代替 2.05 Content 响应; 2.03 Valid 响应随后在响应选项中回显该特定 ETag.
实际上, 客户端可确定 stored representation 中是否有任何一个是当前的 (见 Section 5.6.2), 而无需再次传输它们.
ETag Option 可以在 请求中出现零次, 一次或多次.
5.10.7. Location-Path and Location-Query
Location-Path 和 Location-Query Option 共同指示一个 relative URI, 其由绝对路径, 查询字符串 或二者组成. 这些选项的组合包含在 2.01 (Created) 响应中, 用于指示作为 POST 请求结果创建的 resource 位置 (见 Section 5.8.2). 该 location 相对于请求 URI 解析.
如果带有一个或多个 Location-Path 和/或 Location-Query Option 的响应经过一个解释这些选项的 缓存, 且隐含 URI 标识一个或多个当前 已存储响应, 则这些 条目 必须被标记为 非新鲜.
每个 Location-Path Option 指定到 resource 的 绝对路径的一个 segment, 每个 Location-Query Option 指定一个参数化 resource 的 argument. Location-Path 和 Location-Query Option 可包含任何 字符序列. 不执行 percent-encoding. Location-Path Option 的值不得为 "." 或 "..".
从选项构造 location URI 的步骤类似 Section 6.5, 但跳过前五步, 且结果是 relative URI-reference, 随后相对于请求 URI 解释. 注意, 以这种方式构造的 relative URI-reference 始终包含 绝对路径 (例如, 省略 Location-Path 但提供 Location-Query 意味着 URI 中的 path component 为 "/").
用于计算 relative URI-reference 的选项统称为 Location-* 选项. 除 Location-Path 和 Location-Query 外, 未来可能定义更多 Location-* 选项, 并已保留选项编号128, 132, 136 和 140. 如果这些保留选项编号中任一项除 Location-Path 和/或 Location-Query 外出现且不受支持, 则必须返回 4.02 (Bad Option) error.
5.10.8. Conditional Request Options
conditional 请求选项使 客户端能请求服务器仅在选项指定的某些条件满足时执行请求.
对这些选项中的每一个, 如果给定条件不满足, 服务器不得执行所请求 method. 相反, 服务器必须以 4.12 (Precondition Failed) Response Code 响应.
如果条件满足, 服务器如同 conditional 请求选项不存在一样执行请求 method.
如果请求在没有 conditional 请求选项时会导致 2.xx 或 4.12 以外的任何 Response Code, 则任何 conditional 请求选项可以被忽略.
5.10.8.1. If-Match
If-Match Option 可以用于使请求以 target resource 的一个或多个 representation 的 ETag 当前存在或当前值为条件. If-Match 通常适用于 PUT 请求等 resource update 请求, 作为在多个客户端并行作用于同一 resource 时防止意外覆盖的方式 (即 "lost update" problem).
If-Match 选项的值是 ETag 或 empty string. 带 ETag 的 If-Match 选项匹配具有完全相同 ETag 的 representation. 带 empty value 的 If-Match 选项匹配任何现有 representation (即它将 precondition 置于 target resource 的任何当前 representation 存在性上).
If-Match Option 可出现多次. 如果任一选项匹配, 则条件满足.
如果有一个或多个 If-Match Option, 但没有任何选项匹配, 则条件不满足.
5.10.8.2. If-None-Match
If-None-Match Option 可以用于使请求以 target resource 不存在为条件. If-None-Match 对 PUT 请求等 resource creation 请求有用, 可在多个客户端并行作用于同一 resource 时防止意外覆盖. If-None-Match Option 不携带值.
如果 target resource 存在, 则条件不满足.
(在一个请求中组合 If-Match 和 If-None-Match 选项用处不大, 因为这样条件永远不会满足.)
5.10.9. Size1 Option
Size1 选项提供请求中 resource representation 的 大小信息. 选项值是整数 byte 数. 它主要用于 block-wise transfer [BLOCK]. 在本规范中, 它用于 4.13 响应 (Section 5.9.2.9), 以指示服务器能够且愿意处理的请求实体最大大小.