STOMP协议规范,版本1.2
原文链接:https://stomp.github.io/stomp-specification-1.2.html
翻译如下:
抽象
STOMP是一种简单的互操作协议,旨在通过中介服务器在客户端之间传递异步消息。它为这些客户端和服务器之间传递的消息定义了基于文本的有线格式。
STOMP已经投入使用了多年,并且得到了许多消息代理和客户端库的支持。该规范定义了STOMP 1.2协议,并且是STOMP 1.1的更新。
请将反馈发送到stomp-spec@googlegroups.com邮件列表。
概观
背景
STOMP是由于需要通过脚本语言(例如Ruby,Python和Perl)连接到企业消息代理而产生的。在这样的环境中,通常在逻辑上执行简单的操作,例如“可靠地发送单个消息并断开连接”或“在给定目的地上消耗所有消息”。
它是其他开放消息协议(例如AMQP)和JMS代理(例如OpenWire)中使用的实现特定有线协议的替代。它通过覆盖一小部分常用消息传递操作而不提供全面的消息传递API来与众不同。
最近,STOMP已经发展成为一种协议,就其现在提供的线级功能而言,可以在这些简单的用例之后使用,但仍保持其简单性和互操作性的核心设计原则。
协议概述
STOMP是基于帧的协议,其帧以HTTP为模型。框架由命令,一组可选的标头和可选的主体组成。STOMP基于文本,但也允许传输二进制消息。STOMP的默认编码为UTF-8,但它支持消息正文的替代编码的规范。
STOMP服务器被建模为可以向其发送消息的一组目标。STOMP协议将目标视为不透明字符串,并且其语法是服务器实现特定的。此外,STOMP并未定义目的地的传递语义。目的地的传递或“消息交换”的语义可能因服务器而异,甚至因目的地而异。这使服务器可以利用STOMP支持的语义进行创新。
STOMP客户端是一种用户代理,可以以两种(可能同时)模式运行:
- 作为生产者,通过
SEND
框架将消息发送到服务器上的目标 作为消费者,发送
SUBSCRIBE
给定目标的框架,并从服务器接收消息作为MESSAGE
框架。
协议变更
STOMP 1.2在很大程度上向后兼容STOMP 1.1。只有两个不兼容的更改:
现在可以用回车加换行符代替仅换行符来结束框架行
- 消息确认已简化,现在使用专用报头
除此之外,STOMP 1.2没有引入任何新功能,而是着重于阐明规范的某些方面,例如:
- 重复的帧头条目
- 利用
content-length
和content-type
头 STOMP
服务器所需的框架支持- 连接缠绵
- 订阅和交易标识符的范围和唯一性
-
设计哲学
推动STOMP设计的主要理念是简单性和互操作性。
STOMP被设计为一种轻量级协议,易于在客户端和服务器端以多种语言实现。特别是,这意味着对服务器的体系结构没有太多限制,并且诸如目标命名和可靠性语义之类的许多功能是特定于实现的。
在本规范中,我们将注意到STOMP 1.2未明确定义的服务器功能。您应查阅STOMP服务器的文档,以获取这些功能的实施特定细节。一致性
本文档中的关键词“必须”,“不得”,“必须”,“应”,“不得”,“应”,“应不”,“推荐”,“可以”和“可选”是按照RFC 2119中的描述进行解释。
实现可以对不受约束的输入施加特定于实现的限制,例如,防止拒绝服务攻击,防止内存用完或解决平台特定的限制。
本规范定义的一致性类是STOMP客户端和STOMP服务器。STOMP框架
STOMP是一种基于帧的协议,该协议假定其下具有可靠的2路流网络协议(例如TCP)。客户端和服务器将使用通过流发送的STOMP帧进行通信。框架的结构如下:
COMMAND
header1:value1
header2:value2
Body^@
该帧以一个以行尾(EOL)结束的命令字符串开头,该字符串由一个可选的回车符(八位位组13)和一个必需的换行符(八位位组10)组成。该命令后是零个或多个
<key>:<value>
格式的标题条目。每个标题条目都由EOL终止。空行(即额外的EOL)表示标题的结尾和正文的开头。然后,主体后跟NULL八位位组。本文档中的示例将使用^@
ASCII中的control- @表示NULL八位位组。NULL八位位组后面可以有多个EOL(可选)。有关如何解析STOMP帧的更多详细信息,请参见本文档的“ 增强BNF”部分。
本文档中引用的所有命令和标头名称均区分大小写。值编码
命令和标头以UTF-8编码。除
CONNECT
和帧外的所有帧都CONNECTED
将转义在生成的UTF-8编码报头中发现的任何回车,换行或冒号。
需要转义以允许标头键和值包含那些帧标头定界八位字节作为值。的CONNECT
和CONNECTED
帧不逃脱回车,换行或结肠八位位组,以保持向后兼容STOMP 1.0。
C样式字符串文字转义用于对在UTF-8编码的标头中找到的任何回车符,换行符或冒号进行编码。解码帧头时,必须应用以下转换: \r
(八位字节92和114)转换为回车(八位字节13)\n
(八位字节92和110)转换为换行(八位字节10)\c
(八位位组92和99)转换为:
(八位位组58)\\
(八位位组92和92)转换为\
(八位位组92)
\t
必须将未定义的转义序列(如(八位位组92和116))视为致命的协议错误。相反,在编码帧头时,必须应用逆变换。
STOMP 1.0规范包括许多示例帧,这些帧的标头中带有填充,并且实现了许多服务器和客户端以修剪或填充标头值。如果应用程序要发送不应修剪的标头,则会导致问题。在STOMP 1.2中,客户端和服务器务必不要修剪或填充标头以空格。
身体
只有SEND
,MESSAGE
和ERROR
帧可以具有主体。所有其他框架都不得有车身。
标准标题
标头内容长度
所有帧都可以包含一个content-length
头。此标头是消息正文长度的八位字节计数。如果包含content-length
报头,则无论主体中是否存在NULL八位字节,都必须读取此八位字节的数目。帧仍然需要以NULL八位位组终止。
如果框体存在,则SEND
,MESSAGE
和ERROR
帧应当包含一个content-length
报头,以缓解帧解析。如果帧主体包含NULL八位位组,则帧必须包含一个content-length
报头。
标头内容类型
如果框体存在,则SEND
,MESSAGE
和ERROR
帧应当包含一个content-type
报头,以帮助该帧的接收器解释其身体。如果content-type
设置了标题,则其值务必是描述正文格式的MIME类型。否则,接收者应该认为该主体是二进制斑点。
以MIME类型开头的隐含文本编码为text/
UTF-8。如果您使用的是带有不同编码的基于文本的MIME类型,则应该附加;charset=<encoding>
到MIME类型。例如, text/html;charset=utf-16
如果您以UTF-16编码发送HTML正文,则应使用。该;charset=<encoding>
也应该得到追加到任何非text/
MIME类型的可以解释为文本。一个很好的例子是UTF-8编码的XML。它content-type
应该设置为 application/xml;charset=utf-8
所有STOMP客户端和服务器都必须支持UTF-8编码和解码。因此,为了在异构计算环境中实现最大的互操作性,建议使用UTF-8对基于文本的内容进行编码。
标头收据
除CONNECT
MAY 以外的任何客户端帧都将receipt
使用任意值指定标头。这将导致服务器用RECEIPT
帧确认对客户端帧的处理(有关更多详细信息,请参见RECEIPT帧)。
SEND
destination:/queue/a
receipt:message-12345
hello queue a^@
重复的标题条目
由于消息传递系统可以按类似于SMTP的存储和转发拓扑进行组织,因此一条消息可能会在到达使用者之前经过多个消息传递服务器。STOMP服务器可以通过在消息之前添加标头或在消息中就地修改标头来“更新”标头值。
如果客户端或服务器收到重复的帧头条目,则仅第一个头条目应被用作头条目的值。后续值仅用于维护标头状态更改的历史记录,可以忽略。
例如,如果客户收到:
MESSAGE
foo:World
foo:Hello
^@
大小限制
为了防止恶意客户端利用服务器中的内存分配,服务器可以在以下方面设置最大限制:
- 单个帧中允许的帧头数
- 标题行的最大长度
- 镜框的最大尺寸
如果超出了这些限制,服务器应该向客户端发送一个ERROR
帧,然后关闭连接。
连接缠结
STOMP服务器必须能够支持快速连接和断开连接的客户端。
这意味着服务器可能仅允许关闭的连接在重置连接之前短时间徘徊。
结果,在重置套接字之前,客户端可能没有收到服务器发送的最后一个帧(例如,一个ERROR
帧或RECEIPT
响应该 DISCONNECT
帧的帧)。
连
STOMP客户端通过发送以下CONNECT
帧来启动到服务器的流或TCP连接:
CONNECT
accept-version:1.2
host:stomp.github.org
^@
如果服务器接受连接尝试,它将以以下CONNECTED
帧响应 :
CONNECTED
version:1.2
^@
服务器可以拒绝任何连接尝试。服务器应该用一个ERROR
框架回应,解释为什么拒绝连接,然后关闭连接。
CONNECT或STOMP框架
STOMP服务器必须STOMP
以与CONNECT
帧相同的方式处理帧。STOMP 1.2客户端应继续使用该CONNECT
命令以保持与STOMP 1.0服务器的向后兼容性。
使用STOMP
框架而不是框架的客户端CONNECT
将只能连接到STOMP 1.2服务器(以及某些STOMP 1.1服务器),但是优点是协议嗅探器/鉴别器将能够区分STOMP连接和HTTP连接。 。
STOMP 1.2客户端必须设置以下标头:
accept-version
:客户端支持的STOMP协议版本。有关更多详细信息,请参见协议协商。host
:客户端希望连接的虚拟主机的名称。建议客户端将此设置为建立套接字所依据的主机名,或设置为其选择的任何名称。如果此头与已知的虚拟主机不匹配,则支持虚拟主机的服务器可以选择一个默认的虚拟主机或拒绝连接。
STOMP 1.2客户端可以设置以下头:
login
:用于对受保护的STOMP服务器进行身份验证的用户标识符。passcode
:用于对受保护的STOMP服务器进行身份验证的密码。heart-beat
:心跳设置。
连接框架
STOMP 1.2服务器必须设置以下标头:
version
:会话将使用的STOMP协议的版本。有关更多详细信息,请参见协议协商。
STOMP 1.2服务器可以设置以下头:
heart-beat
:心跳设置。session
:唯一标识会话的会话标识符。server
:包含有关STOMP服务器的信息的字段。该字段必须包含一个服务器名字段,并且可以在其后跟可选的注释字段,并用空格分隔。
服务器名称字段由名称令牌和后面的可选版本号令牌组成。server = name ["/" version] *(comment)
例:server:Apache/1.3.9
协议协商
从STOMP 1.1开始,
CONNECT
框架必须包含accept-version
标头。应该将其设置为客户端支持的递增STOMP协议版本的逗号分隔列表。如果accept-version
缺少标头,则表示客户端仅支持该协议的1.0版。
其余会话将使用的协议将是客户端和服务器共同拥有的最高协议版本。
例如,如果客户端发送:CONNECT
accept-version:1.0,1.1,2.0
host:stomp.github.org
^@
服务器将以与客户端相同的最高版本的协议进行响应:
CONNECTED
version:1.1
^@
如果客户端和服务器不共享任何通用协议版本,则服务器必须使用
ERROR
类似于以下内容的帧进行响应,然后关闭连接:ERROR
version:1.2,2.1
content-type:text/plain
Supported protocol versions are 1.2 2.1^@
心脏跳动
心跳可以可选地用于测试基础TCP连接的健康状况,并确保远程端处于活动状态并正常运行。
为了实现心跳,每一方都必须声明其可以做什么以及另一方希望做什么。这是在STOMP会话的开始时发生的,方法是heart-beat
在CONNECT
和CONNECTED
帧中添加标头 。
使用时,heart-beat
标头必须包含两个以逗号分隔的正整数。
第一个数字表示帧发送者可以执行的操作(发出心跳):0表示无法发送心跳
- 否则,这是可以保证的心跳之间的最小毫秒数
第二个数字代表帧的发送者想要得到的(传入的心跳):
- 0表示它不希望接收心跳
- 否则,这是心跳之间所需的毫秒数
所述heart-beat
报头是可选的。丢失的heart-beat
报头必须与“心跳:0,0”报头一样对待,即:对方无法发送并且不想接收心跳。
该heart-beat
头提供足够的信息,使每一方都可以找出是否可用于心脏,节拍,在哪个方向,并与频率。
更正式地说,初始帧如下所示:
CONNECT
heart-beat:<cx>,<cy>
CONNECTED:
heart-beat:<sx>,<sy>
对于从客户端到服务器的心跳:
- 如果
<cx>
为0(客户端无法发送心跳)或<sy>
为0(服务器不希望接收心跳),则不会有 - 否则,每MAX(
<cx>
,<sy>
)毫秒都会有一次心跳
在另一方向,<sx>
并<cy>
使用相同的方法。
关于心跳本身,通过网络连接接收到的任何新数据都表明远端处于活动状态。在给定的方向上,如果预期每<n>
毫秒心跳:
- 发送方必须至少每
<n>
毫秒通过网络连接发送一次新数据 - 如果发送方没有实际的STOMP帧要发送,则必须发送行尾(EOL)
- 如果在至少
<n>
毫秒的时间窗口内,接收方没有收到任何新数据,则它可以认为连接无效 -
客户框架
客户端可以发送不在此列表中的帧,但是对于这样的帧,STOMP 1.2服务器可以响应一个
ERROR
帧,然后关闭连接。 SUBSCRIBE
UNSUBSCRIBE
BEGIN
COMMIT
ABORT
ACK
NACK
DISCONNECT
发送
该SEND
帧将消息发送到消息系统中的目的地。它有一个REQUIRED标头,destination
它指示将消息发送到的位置。SEND
框架的主体是要发送的消息。例如:
这会将消息发送到名为的目的地SEND
destination:/queue/a
content-type:text/plain
hello queue a
^@
/queue/a
。请注意,STOMP将此目的地视为不透明字符串,并且目的地名称不假定任何传递语义。您应该查阅STOMP服务器的文档,以了解如何构造目标名称,该名称为您提供了应用程序所需的交付语义。
消息的可靠性语义也是服务器特定的,并且将取决于所使用的目标值和其他消息标头,例如transaction
标头或其他服务器特定的消息标头。SEND
支持transaction
允许事务发送的标头。SEND
框架应该包含一个content-length
标头和一个content-type
标头(如果存在正文)。
一个应用程序可以向SEND
框架添加任何用户定义的头文件。用户定义的标头通常用于允许使用者使用SUBSCRIBE
框架上的选择器根据应用程序定义的标头过滤消息。用户定义的报头必须在MESSAGE
帧中传递。
如果服务器SEND
由于某种原因无法成功处理该帧,则服务器必须向客户端发送一个ERROR
帧,然后关闭连接。订阅
该SUBSCRIBE
帧用于注册以收听给定的目的地。与SEND
框架一样,该SUBSCRIBE
框架也需要destination
标头,以指示客户端要订阅的目的地。此后,在订阅目标上接收到的所有消息都将作为MESSAGE
帧从服务器传递到客户端。所述ack
报头控制消息确认模式。
例:
如果服务器无法成功创建订阅,则服务器必须向客户端发送一SUBSCRIBE
id:0
destination:/queue/foo
ack:client
^@
ERROR
帧,然后关闭连接。
STOMP服务器可以支持附加的服务器特定的头,以定制订阅的传递语义。有关详细信息,请查阅服务器的文档。订阅ID标头
由于单个连接可以具有与服务器的多个打开的订阅,因此id
报头必须包含在框架中以唯一地标识订阅。的id
报头允许客户端和服务器到随后的涉及MESSAGE
或UNSUBSCRIBE
帧到原来的订阅。
在同一连接内,不同的订阅必须使用不同的订阅标识符。订阅ack标头
为有效的值ack
头是auto
,client
,或client-individual
。如果未设置标题,则默认为auto
。
当ack
模式为时auto
,客户端不需要ACK
为接收到的消息发送服务器帧。服务器将假定客户端在将其发送到客户端后就已收到该消息。此确认模式可能导致发送到客户端的消息丢失。
当ack
模式client
为时,客户端必须发送ACK
其处理的消息的服务器 帧。如果在客户端发送ACK
该消息的帧之前连接失败,则服务器将假定该消息尚未处理,可以将消息重新传递给另一个客户端。ACK
客户端发送的 帧将被视为累积确认。这意味着确认将对ACK
框架中指定的消息以及ACK
“ ed”消息之前发送给订阅的所有消息进行操作。
如果客户端没有处理某些消息,它应该发送NACK
帧来告诉服务器它没有使用这些消息。
当ack
模式为时client-individual
,确认的操作与client
确认模式一样,不同之处在于客户端发送的ACK
或NACK
帧不是累积的。这意味着 后续消息的ACK
或NACK
框架绝不能导致先前消息得到确认。退订
该UNSUBSCRIBE
框架用于删除现有订阅。删除订阅后,STOMP连接将不再从该订阅中接收消息。
由于单个连接可以具有与服务器的多个打开的订阅,因此id
标头必须包含在框架中以唯一地标识要删除的订阅。该头必须与现有订阅的订阅标识符匹配。
例:UNSUBSCRIBE
id:0
^@
ACK
ACK
用于确认使用client
或client-individual
确认来自订阅的消息的使用。从此类订阅收到的任何消息都不会被视为已使用,直到已通过确认消息为止ACK
。
该ACK
帧必须包括一个id
报头匹配ack
的报头MESSAGE
被确认。可选地,transaction
可以指定一个头,指示消息确认应该是命名事务的一部分。ACK
id:12345
transaction:tx1
^@
NACK
NACK
与相对ACK
。它用于告诉服务器客户端没有使用该消息。然后,服务器可以将消息发送到其他客户端,将其丢弃,或将其放入死信队列。确切的行为是特定于服务器的。NACK
采用与ACK
:(id
必需)和transaction
(可选)相同的标题。NACK
适用于任一单一的消息(如果预订的ack
模式是client-individual
),或发送之前,尚未所有消息ACK
“编或NACK
” ED(如果订阅的ack
模式是client
)。开始
BEGIN
用于开始交易。在这种情况下,事务适用于发送和确认-事务期间发送或确认的任何消息都将基于事务自动进行处理。
所述BEGIN
transaction:tx1
^@
transaction
报头是必须的,并且所述事务标识符将被用于SEND
,COMMIT
,ABORT
,ACK
,和NACK
帧,以将它们绑定到指定的事务。在同一连接内,不同的事务必须使用不同的事务标识符。
如果客户端发送DISCONNECT
帧或TCP连接由于任何原因失败,则任何尚未提交的已启动事务都将隐式中止。承诺
COMMIT
用于提交正在进行的事务。
所述COMMIT
transaction:tx1
^@
transaction
报头是必需的,必须指定该事务的标识符提交。中止
ABORT
用于回滚正在进行的事务。
所述ABORT
transaction:tx1
^@
transaction
报头是必需的,必须指定该事务的标识符以中止。断开
客户端可以随时通过关闭套接字与服务器断开连接,但是不能保证服务器已接收到先前发送的帧。为了进行正常关机,在确保客户端已收到服务器之前所有先前帧的情况下,客户端应:
发送
DISCONNECT
带有receipt
标头集的帧。例:DISCONNECT
receipt:77
^@
等待
RECEIPT
帧响应DISCONNECT
。例:RECEIPT
receipt-id:77
^@
关闭插座。
请注意,如果服务器关闭套接字末端的速度过快,则客户端可能永远不会收到预期的RECEIPT
帧。有关更多信息,请参见“ 连接延迟”部分。
客户端在发送帧后不得再发送任何帧DISCONNECT
。
服务器框架
服务器有时会发送帧到客户端(除了初始CONNECTED
帧)。这些框架可能是以下之一:
MESSAGE
RECEIPT
ERROR
信息
MESSAGE
框架用于将消息从订阅传递到客户端。
该MESSAGE
帧必须包含一个destination
报头指示该消息被发送到目的地。如果消息已使用STOMP发送,则此destination
报头应与相应SEND
帧中使用的报头相同。
该MESSAGE
框架还必须包含一个message-id
与用于该消息和一个唯一的标识符表头subscription
匹配所接收消息的订阅的标识符表头。
如果从需要显式确认(client
或client-individual
模式)的订阅接收到消息,则该MESSAGE
帧还必须包含ack
带有任意值的头。该头将用于将消息与后续消息ACK
或NACK
帧相关联。
框架主体包含消息的内容:MESSAGE
subscription:0
message-id:007
destination:/queue/a
content-type:text/plain
hello queue a^@
MESSAGE
框架应该包含一个content-length
标头和一个content-type
标头(如果存在正文)。MESSAGE
除了可能会添加到框架的服务器特定头之外,框架还将包括在将消息发送到目标时出现的所有用户定义的头。请查阅服务器的文档,以了解服务器添加到消息中的特定于服务器的标头。收据
甲RECEIPT
帧被从服务器发送到客户端一旦服务器已经成功地处理请求一个接收到的客户端帧。甲RECEIPT
帧必须包括头receipt-id
,其中值是的值receipt
在帧其中这是一个收据首部。
甲RECEIPT
receipt-id:message-12345
^@
RECEIPT
帧是对应的客户端帧已被确认处理由服务器。由于STOMP是基于流的,因此接收也是对服务器已接收到所有先前帧的累积确认 。但是,这些先前的帧可能尚未完全处理。如果客户端断开连接,则服务器应继续处理先前收到的帧。错误
ERROR
如果出现问题,服务器可以发送帧。在这种情况下,必须在发送ERROR
帧后立即关闭连接。请参阅下一节有关连接徘徊。
所述ERROR
帧应该包含一个message
报头,并显示错误的简短说明,并且主体可以包含更多详细的信息(或者可以是空的)。 ``` ERROR receipt-id:message-12345 content-type:text/plain content-length:171 message: malformed frame received The message:
MESSAGE destined:/queue/a receipt:message-12345
Hello queue a!
Did not contain a destination header, which is REQUIRED for message propagation. ^@
如果错误与客户端发送的特定帧有关,则服务器应添加其他报头,以帮助识别导致错误的原始帧。例如,如果框架包括收据标头,则`ERROR` 框架应将`receipt-id`标头设置为与`receipt` 错误相关的框架标头的值相匹配。<br />`ERROR`框架应该包含一个 [`content-length`](https://stomp.github.io/stomp-specification-1.2.html#Header_content-length)标头和一个 [`content-type`](https://stomp.github.io/stomp-specification-1.2.html#Header_content-type)标头(如果存在正文)。
<a name="Frames_and_Headers"></a>
## 框架和标题
除了[标准头](https://stomp.github.io/stomp-specification-1.2.html#Standard_Headers)如上所述(`content-length`,`content-type`和`receipt`),这里是在本说明书中,各帧必须或可以使用定义的所有标头:
- `CONNECT`要么`STOMP`
- 必填:`accept-version`,`host`
- 可选:`login`,`passcode`,`heart-beat`
- `CONNECTED`
- 需要: `version`
- 可选:`session`,`server`,`heart-beat`
- `SEND`
- 需要: `destination`
- 可选的: `transaction`
- `SUBSCRIBE`
- 必填:`destination`,`id`
- 可选的: `ack`
- `UNSUBSCRIBE`
- 需要: `id`
- 可选:无
- `ACK`要么`NACK`
- 需要: `id`
- 可选的: `transaction`
- `BEGIN`或`COMMIT`或`ABORT`
- 需要: `transaction`
- 可选:无
- `DISCONNECT`
- 必填:无
- 可选的: `receipt`
- `MESSAGE`
- 要求:`destination`,`message-id`,`subscription`
- 可选的: `ack`
- `RECEIPT`
- 需要: `receipt-id`
- 可选:无
- `ERROR`
- 必填:无
- 可选的: `message`
另外,`SEND`和`MESSAGE`帧可以包含任意用户定义的报头,应该将其视为所携带消息的一部分。而且,该`ERROR`帧应该包含其他报头,以帮助识别导致错误的原始帧。<br />最后,STOMP服务器可以使用其他报头来访问诸如持久性或过期之类的功能。有关详细信息,请查阅服务器的文档。
<a name="Augmented_BNF"></a>
## 增强型BNF
使用HTTP / 1.1 [RFC 2616](http://tools.ietf.org/html/rfc2616#section-2.1)中使用的Backus-Naur格式(BNF)语法可以更正式地描述STOMP会话 。
NULL =
执照
本规范是根据 知识共享署名v3.0 许可获得许可的。