节错误
节相关的错误处理的方式类似流错误流错误, 但是不像流错误那样,节错误是可恢复的; 所以, 他们不会导致XML和当前TCP连接的中止. 反之, 发现错误条件的实体返回一个错误节, 它是一个这样的节:
-
- 是和触发这个错误的已生成的节同种类型(message, presence, 或 IQ)
- 'type'属性值设为"error"
- 通常是把已生成的节的'from'和'to'互换
- 镜像触发这个错误的已生成的节的'id'属性(如果有的话)
- 包含一个<error/>子元素以指明错误条件并且对发送者可以采取的补救措施提供一个暗示(然而, 不可能总是能够不补救这个错误)
规则
以下规则适用于节错误:
-
- 检测到和节相关的错误条件的接收或处理实体应该返回一个错误节(对于IQ节必须这么做).
- 该错误节应该简单地把生成的节中的'from'和'to'地址互换, 除非这么做将会 (1) 导致信息泄漏(参见[RFC6120#信息泄露|13.10]])或其他违反安全, 或 (2) 强迫错误节的发送者在该错误节的'from'或'to'地址中包含一个异常的JID.
- 如果生成的节是<message/>或<presence/>并且包含了'id'属性,那么该错误节必须也包含'id'属性. 如果生成的节是<iq/>,那么该错误节必须包含一个'id'属性. 在所有情况下, 'id'属性的值必须和生成节的相同(或者是空,如果生成的节没有包含'id'属性).
- 错误节必须包含一个<error/>子元素.
- 返回错误节的实体可以传递它的JID给生成节的发送者(例如, 为了诊断或跟踪的目的),通过附加一个'by'属性到<error/>子元素.
- 返回错误节的实体可以包含被发送的原始XML,这样发送者能够检查, 如果必要的话, 并在尝试重发之前纠正该XML(然而, 这只是出于礼貌,并且原实体不能(MUST NOT)依赖接收到的原始载荷). 自然地, 该实体不能(MUST NOT)包含原始数据,如果它不是格式良好的XML, 违反XMPP的XML限制(见11.1), 或反而是有害的(例如, 超出大小限制).
- 如果'type'属性值不是"error"(或如果没有'type'属性), 不能(MUST NOT)包含一个<error/>子元素.
- 接收到错误节的实体不能(MUST NOT)以更多的错误节来应答这个节; 这有助于防止死循环.
语法
节相关的错误的语法如下, 这里展示的用方括号'['和']'括起来的XML数据是可选的, 'intended-recipient' 是原始节指定的地址的那个实体的JID, 'sender' 是原始实体的JID, 而 'error-generator' 是检测到错误的并方会错误节的那个实体.
<stanza-kind from='intended-recipient' to='sender' type='error'> [OPTIONAL to include sender XML here] <error [by='error-generator'] type='error-type'> <defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> [<text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' xml:lang='langcode'> OPTIONAL descriptive text </text>] [OPTIONAL application-specific condition element] </error> </stanza-kind>
"stanza-kind"必须是 message, presence, 或 iq 之一.
"error-type" 必须是以下之一:
-
- auth -- 在提供身份之后重试
- cancel -- 不要重试 (该错误不能加以弥补)
- continue -- 继续 (这个条件只是个警告)
- modify -- 在修改发送的数据之后重试
- wait -- 等待之后重试 (该错误是暂时的)
"defined-condition"必须符合8.3.3定义的节错误条件之一. 然而, 因为将来可能会发生额外的错误条件, 如果实体接受到一个它不理解的节错误条件,那么它必须把这个未知的条件当成<undefined-condition/> (8.3.3.21). 如果一个XMPP协议扩展的设计者或一个XMPP实现的开发者需要未在本协议中定义的节错误条件的通讯, 他们可以定义应用特有的命名空间所限定的应用特有的错误条件元素来实现这个目标.
<error/>元素:
-
- 必须包含一个已定义的条件元素.
- 可以包含一个包含XML字符串数据的<text/>子元素,用来描述错误的详细信息; 这个元素必须由'urn:ietf:params:xml:ns:xmpp-stanzas'命名空间来限定并且应该拥有'xml:lang'属性来指定该XML字符串数据的自然语言.
- 可以包含一个用于应用特有的错误条件的子元素; 这个元素必须由一个应用特有的命名空间来限定,以定义该元素的语法和语义.
<text/>元素是可选的. 如果包含了它, 它仅被用于提供描述和诊断信息以补充说明已定义条件或应用特有的条件的含义. 它不能(MUST NOT)被应用程序当成编程信息来解释. 它不应该被用于向自然人用户展示错误消息, 但是可以被附加在该已定义条件元素(以及, 可选的, 应用特有的条件元素)的错误消息上展示.
- 互操作性备注: 定义于 RFC3920的语法包含了一个遗留的'code'属性, 它的语义已经被已定义的条件元素取代; 关于已定义的条件元素和遗留的'code'属性值之间的对应关系,可以在 XEP‑0086]找到.
已定义的条件
以下条件是已定义好用于节错误的.
error-type 的值是被推荐用于每个已定义的条件通常预期的类型; 无论如何, 在某些情况下不同的类型可能更合适.
bad-request
发送者发送的节里包含的XML不符合适当的schema或不能被拥有(例如, IQ节的'type'属性包含一个不能识别的值, 或一个被已知的命名空间限定的元素但是违反了该元素的已定义的语法); 相关的错误类型应该是"modify".
C: <iq from='juliet@im.example.com/balcony' id='zj3v142b' to='im.example.com' type='subscribe'> <ping xmlns='urn:xmpp:ping'/> </iq> S: <iq from='im.example.com' id='zj3v142b' to='juliet@im.example.com/balcony' type='error'> <error type='modify'> <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
conflict
访问未被授权,因为一个现存的资源使用了相同的名字或地址; 相关的错误类型应该是"cancel".
C: <iq id='wy2xa82b4' type='set'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <resource>balcony</resource> </bind> </iq> S: <iq id='wy2xa82b4' type='error'> <error type='cancel'> <conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
feature-not-implemented
出现在XML节里的特性没有被预定的接收方或中间服务器实现,所以该节无法被处理(例如, 该实体知道该命名空间但是不认识元素名); 相关的错误类型应该是"cancel" 或 "modify".
C: <iq from='juliet@im.example.com/balcony' id='9u2bax16' to='pubsub.example.com' type='get'> <pubsub xmlns='http://jabber.org/protocol/pubsub'> <subscriptions/> </pubsub> </iq> E: <iq from='pubsub.example.com' id='9u2bax16' to='juliet@im.example.com/balcony' type='error'> <error type='cancel'> <feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <unsupported xmlns='http://jabber.org/protocol/pubsub#errors' feature='retrieve-subscriptions'/> </error> </iq>
forbidden
请求的实体没有必要的许可来执行一个只允许特定授权角色或个体来完成的动作(即, 它通常和授权而不是验证有关); 相关的错误类型应该是"auth".
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='characters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='characters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony' type='error'> <error type='auth'> <forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
gone
接收者或服务器无法再用这个地址联系到, 通常是永久意义上的(和<redirect/>错误条件相反, 它被用于临时的地址失败); 相关的错误类型应该是"cancel"并且该错误节应该包含一个新的地址(如果可用的话)作为<gone/>元素的XML字符串数据(它必须是一个实体可以联系的唯一资源标识符URI或国际化资源标识符IRI, 典型的是一个XMPP‑URI定义的XMPP IRI.
C: <message from='juliet@im.example.com/churchyard' id='sj2b371v' to='romeo@example.net' type='chat'> <body>Thy lips are warm.</body> </message> S: <message from='romeo@example.net' id='sj2b371v' to='juliet@im.example.com/churchyard' type='error'> <error by='example.net' type='cancel'> <gone xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'> xmpp:romeo@afterlife.example.net </gone> </error> </message>
internal-server-error
服务器发生了错误的配置或其他阻止它处理改节的内部错误; 相关的错误类型应该是"cancel".
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='characters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='characters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony' type='error'> <error type='cancel'> <internal-server-error xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
item-not-found
找不到请求的JID地址或条目; 相关的错误类型应该是"cancel".
C: <presence from='userfoo@example.com/bar' id='pwb2n78i' to='nosuchroom@conference.example.org/foo'/> S: <presence from='nosuchroom@conference.example.org/foo' id='pwb2n78i' to='userfoo@example.com/bar' type='error'> <error type='cancel'> <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
- 安全警告: 如果这样做将会提供预定的接收者的网络可用性信息给一个未被授权知道这些信息的实体(关于联机状态信息授权的更多细节讨论,参考 XMPP-IM联机状态订阅的讨论),那么应用不能(MUST NOT)返回这个错误; 相反它应该返回一个<service-unavailable/>错误( 8.3.3.19).
jid-malformed
发送的实体所提供(例如, 在资源绑定的时候)或与之通讯(例如, 一个节的'to'地址)的XMPP地址或其中一部分违反了XMPP‑ADDR定义的规则; 相关的错误类型应该是"modify".
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='ch@r@cters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='ch@r@cters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony' type='error'> <error by='muc.example.com' type='modify'> <jid-malformed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
- 实现备注: 强制XMPP本地部分的格式主要是相关帐号或实体所在的服务的责任(例如, example.com 服务负责返回所有和格式 <localpart@example.com> 相关的 <jid-malformed/> 错误), 而强制XMPP域部分的格式主要是由路由一个节到域部分所指定的服务的那个服务的责任 (例如, example.org 服务负责返回该服务尝试发送的目标JID <localpart@example.com>的格式的 <jid-malformed/> 错误 ). 无论如何, 任何检测到格式错误的JID的实体可以返回该错误.
not-acceptable
接收者或服务器理解该请求但是不能处理它,因为该请求不符合该接收者或服务器的标准(例如, 请求订阅信息但是未同时包含接收者需要的配置参数); 相关的错误类型应该是"modify".
C: <message to='juliet@im.example.com' id='yt2vs71m'> <body>[ ... the-emacs-manual ... ]</body> </message> S: <message from='juliet@im.example.com' id='yt2vs71m'> <error type='modify'> <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </message>
not-allowed
接收者或服务器不允许任何实体执行该动作(例如, 向列入黑名单的域发送消息); 相关的错误类型应该是"cancel".
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='characters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='characters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony' type='error'> <error type='cancel'> <not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
not-authorized
发送者在被允许执行某动作之前需要提供凭证, 或已经提供了错误的凭证("not-authorized"的提法, 来源于HTTP的"401 Unauthorized"错误, 可能导致读者认为这个条件是和授权相关的, 但其实它通常用于验证相关的领域); 相关的错误类型应该是"auth".
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='characters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='characters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony'> <error type='auth'> <not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
policy-violation
实体违反了一些本地服务策略(例如, 一个消息包含了服务禁止的单词)而服务器可以选择在<text/>元素里或在应用特有的条件元素里指定策略; 相关的错误类型应该是"modify"或"wait",取决于被违反的策略.
(在下例中, 客户端发送一个包含了根据服务器的本地服务策略被禁止的单词的XMPP消息.)
C: <message from='romeo@example.net/foo' to='bill@im.example.com' id='vq71f4nb'> <body>%#&@^!!!</body> </message> S: <message from='bill@im.example.com' id='vq71f4nb' to='romeo@example.net/foo'> <error by='example.net' type='modify'> <policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </message>
预期的接收者暂时不可用, 正在维护, 等等; 相关的错误类型应该是"wait".
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='characters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='characters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony'> <error type='wait'> <recipient-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
- 安全警告: 如果这么做将提供关于预期接收者的网络可用性的信息给一个没有被授权可以知道这类信息的实体(对于联机状态授权方面的讨论的更多细节, 参考联机状态信息订阅的讨论 XMPP‑IM中),应用不能(MUST NOT)返回这个错误; 反之,它必须返回一个<service-unavailable/> 节错误( 8.3.3.19).
redirect
接收者或服务器重定向该信息的请求到另一个实体, 典型的临时发生的情形(和<gone/>错误条件相反, 它用于永久性的地址错误); 相关的错误类型应该是"modify",并且该错误节应该在<redirect/>元素的XML字符串数据中包含替代的地址(它必须是一个发送者可以与之通讯的URI或IRI, 通常是一个XMPP‑URI定义的XMPP IRI).
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='characters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='characters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony' type='error'> <error type='modify'> <redirect xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'> xmpp:characters@conference.example.org </redirect> </error> </presence>
- 安全警告: 接收到一个节级别的重定向的应用应该向自然人用户警告这个重定向尝试并且在和包含在该<redirect/>元素的XML字符串数据中的地址代表的实体通讯之前请求批准, 因为那个实体可能有不同的身份或可能强制执行不同的安全策略. XMPP节的点对点验证或签名有助于减轻这个风险, 因为它将允许发送者来决定是否被重定向到的实体和开始尝试联系的实体是同一个身份. 应用可以有一个策略规定只有已经验证过接收实体才能重定向. 另外, 在成功地重定向了一定次数之后应用应该中止通讯尝试(例如, 至少2次但不超过5次).
registration-required
请求的实体没有被授权访问请求的服务,因为需要事先注册(提前注册的例子包括XMPP多用户聊天XEP-0045中仅限会员的房间和到非XMPP即时消息服务的网关, 传统上使用网关XEP‑0100是需要注册的); 相关的错误类型应该是"auth".
C: <presence from='juliet@im.example.com/balcony' id='y2bs71v4' to='characters@muc.example.com/JulieC'> <x xmlns='http://jabber.org/protocol/muc'/> </presence> E: <presence from='characters@muc.example.com/JulieC' id='y2bs71v4' to='juliet@im.example.com/balcony'> <error type='auth'> <registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </presence>
remote-server-not-found
一个远程服务器或预期的接收者的JID的一部分所代表的服务不存在或不能解析(例如, 没有 _xmpp-server._tcp DNS SRV记录, A记录或AAAA记录解析也失败了, 或A/AAAA查询成功了但是在IANA注册了的端口5269上没有应答); 相关错误类型应该是"cancel".
C: <message from='romeo@example.net/home' id='ud7n1f4h' to='bar@example.org' type='chat'> <body>yt?</body> </message> E: <message from='bar@example.org' id='ud7n1f4h' to='romeo@example.net/home' type='error'> <error type='cancel'> <remote-server-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </message>
remote-server-timeout
远程服务器或作为预定的接收者的全JID的一部分(或履行请求所需要的)的服务能被解析但是无法在合理的时间内与之建立通讯(例如, 无法在解析到的IP地址和端口上建立一个XML流, 或可以建立一个XML流但是因为TLS, SASL, Server Dialback的问题导致流协商失败, 等等); 相关的错误类型应该是"wait" (除非该错误是更永久性的, 例如, 远程服务器能被找到但是无法被认证或它违反了安全策略).
C: <message from='romeo@example.net/home' id='ud7n1f4h' to='bar@example.org' type='chat'> <body>yt?</body> </message> E: <message from='bar@example.org' id='ud7n1f4h' to='romeo@example.net/home' type='error'> <error type='wait'> <remote-server-timeout xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </message>
resource-constraint
服务器或接收者忙或缺乏必要的系统资源来服务该请求; 相关的错误类型应该是"wait".
C: <iq from='romeo@example.net/foo' id='kj4vz31m' to='pubsub.example.com' type='get'> <pubsub xmlns='http://jabber.org/protocol/pubsub'> <items node='my_musings'/> </pubsub> </iq> E: <iq from='pubsub.example.com' id='kj4vz31m' to='romeo@example.net/foo' type='error'> <error type='wait'> <resource-constraint xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </iq>
服务器或接收者当前未提供被请求的服务; 相关的错误类型应该是"cancel".
C: <message from='romeo@example.net/foo' to='juliet@im.example.com'> <body>Hello?</body> </message> S: <message from='juliet@im.example.com/foo' to='romeo@example.net'> <error type='cancel'> <service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </message>
- 安全警告: 应用程序必须返回一个<service-unavailable/>节错误( 8.3.3.19)而不是<item-not-found/>( 8.3.3.7)或<recipient-unavailable/>( 8.3.3.13), 如果发送后面两个错误将提供关于预期的接收者的网络可用性信息给一个未被授权知道这写信息的实体(详见联机状态信息授权的讨论, 参考 XMPP‑IM).
subscription-required
提出请求的实体没有被授权访问所请求的服务,因为需要事先订阅(事先订阅的例子包括授权接收XMPP‑IM定义的联机状态信息和用于XEP‑0060定义的XMPP发布-订阅的 opt-in 数据种子); 相关的错误类型应该是"auth".
C: <message from='romeo@example.net/orchard' id='pa73b4n7' to='playwright@shakespeare.example.com' type='chat'> <subject>ACT II, SCENE II</subject> <body>help, I forgot my lines!</body> </message> E: <message from='playwright@shakespeare.example.com' id='pa73b4n7' to='romeo@example.net/orchard' type='error'> <error type='auth'> <subscription-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> </error> </message>
undefined-condition
该错误条件不在本列表中的其他错误条件之中; 任何错误类型都可能和本条件有关, 并且除非和应用特有的条件联合在一起,它应该不被使用.
C: <message from='northumberland@shakespeare.example' id='richard2-4.1.247' to='kingrichard@royalty.england.example'> <body>My lord, dispatch; read o'er these articles.</body> <amp xmlns='http://jabber.org/protocol/amp'> <rule action='notify' condition='deliver' value='stored'/> </amp> </message> S: <message from='example.org' id='amp1' to='northumberland@example.net/field' type='error'> <amp xmlns='http://jabber.org/protocol/amp' from='kingrichard@example.org' status='error' to='northumberland@example.net/field'> <rule action='error' condition='deliver' value='stored'/> </amp> <error type='modify'> <undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <failed-rules xmlns='http://jabber.org/protocol/amp#errors'> <rule action='error' condition='deliver' value='stored'/> </failed-rules> </error> </message>
unexpected-request
接收者或服务器理解这个请求但是不希望它在这个时候出现(即, 该请求顺序错了); 相关的错误类型应该是"wait"或"modify".
C: <iq from='romeo@example.net/foo' id='o6hsv25z' to='pubsub.example.com' type='set'> <pubsub xmlns='http://jabber.org/protocol/pubsub'> <unsubscribe node='my_musings' jid='romeo@example.net'/> </pubsub> </iq> E: <iq from='pubsub.example.com' id='o6hsv25z' to='romeo@example.net/foo' type='error'> <error type='modify'> <unexpected-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <not-subscribed xmlns='http://jabber.org/protocol/pubsub#errors'/> </error> </iq>
应用特有的条件
大家知道, 一个应用可以提供应用特有的节错误信息,通过在错误元素中包含一个正确的命名空间的子元素. 典型的, 该应用特有的元素补充或进一步限定一个已定义的元素. 从而, 该<error/>元素将包含两个或三个子元素.
<iq id='ixc3v1b9' type='error'> <error type='modify'> <bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <too-many-parameters xmlns='http://example.org/ns'/> </error> </iq> <message type='error' id='7h3baci9'> <error type='modify'> <undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/> <text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'> [ ... application-specific information ... ] </text> <too-many-parameters xmlns='http://example.org/ns'/> </error> </message>
一个接收到它不理解的应用特有的错误条件的实体必须忽略那个条件但适当处理该错误节的其他部分.