STOMP 协议

STOMP(Simple Text Oriented Messaging Protocol,简单文本定向消息协议)是一种轻量级、基于文本的应用层消息通信协议,运行在TCP、WebSocket等可靠双向流协议之上,用于客户端与消息代理(Broker)之间的异步消息交互。它的设计灵感源自HTTP,以极简的帧结构和标准化的消息语义,解决了原生传输层缺乏消息路由、订阅、确认等能力的问题。

STOMP 最早诞生于脚本语言生态(Ruby、Python、Perl),目标是让各类语言都能低成本接入企业级消息中间件,目前已成为WebSocket场景下最主流的消息子协议之一。

一、版本演进

STOMP 目前有三个正式版本,主流 Broker 均兼容全版本:

  1. STOMP 1.0:初始版本,定义了基础帧结构、连接、收发、订阅等核心能力
  2. STOMP 1.1:新增心跳保活、NACK 否定确认、事务增强、重复头部处理等能力
  3. STOMP 1.2:最新稳定版(2012年发布),优化了心跳协商、流控逻辑、内容长度解析规则,是当前工业界的主流版本

二、核心架构与模型

STOMP 采用经典的客户端-消息代理(Broker) 架构,协议本身只定义通信格式,不强制消息路由语义,具体交付逻辑由 Broker 实现。

1. 角色定义

  • 生产者 :客户端通过 SEND 命令向指定目的地发送消息
  • 消费者 :客户端通过 SUBSCRIBE 命令订阅目的地,接收 Broker 推送的 MESSAGE
  • 消息代理(Broker):负责接收、路由、投递消息,管理订阅关系和会话状态

2. 目的地(Destination)

目的地是 STOMP 中的核心抽象,协议仅将其定义为不透明字符串,具体语义由 Broker 实现决定,行业通用约定:

  • /queue/xxx:队列模式,点对点消息,一条消息只会投递给一个消费者,支持负载均衡
  • /topic/xxx:主题模式,发布/订阅广播,一条消息投递给所有订阅者
  • /user/xxx:用户专属队列,用于定向给单个用户推送消息(Spring 扩展约定)

三、帧格式详解

STOMP 是面向帧的协议,所有通信都通过帧完成,帧结构与 HTTP 高度相似,整体分为 5 个部分:

复制代码
COMMAND          # 命令行(大写)
header1:value1   # 头部,每行一个 key:value
header2:value2
                 # 空行(\n\n),分隔头部和消息体
Body^@           # 消息体 + 结束符(NULL 字节,ASCII 0x00,写作 ^@)

各部分规则说明

  1. 命令行:必须为大写英文字母,以换行符结尾,代表帧的操作类型
  2. 头部key:value 格式,每行一个,顺序无关;支持重复头部,同 key 按顺序拼接
    • content-length:特殊头部,指定消息体的字节长度;若存在则严格按长度读取,不受 NULL 字节影响;若不存在则读到第一个 NULL 字节结束
    • 常用头部:destinationcontent-typemessage-idreceiptack
  3. 空行:头部和消息体的分隔符,必须存在(即使没有消息体)
  4. 消息体:可选,支持文本或二进制数据
  5. 结束符:必须以 NULL 字节(0x00)结尾,标记帧的结束

典型帧示例

客户端连接帧
复制代码
CONNECT
accept-version:1.2
host:localhost
login:admin
passcode:admin

^@
服务端连接响应
复制代码
CONNECTED
version:1.2
session:abc-12345
heart-beat:10000,10000

^@
客户端发送消息
复制代码
SEND
destination:/queue/order
content-type:application/json
content-length:39

{"orderId":"1001","amount":99.9}
^@
服务端推送消息
复制代码
MESSAGE
destination:/topic/news
message-id:msg-001
content-type:text/plain

Hello STOMP Protocol
^@

四、核心命令集

STOMP 命令分为客户端发起命令服务端响应命令两类。

1. 客户端命令

命令 作用
CONNECT 与 Broker 建立连接,协商版本、认证、心跳
SEND 向指定目的地发送消息
SUBSCRIBE 订阅指定目的地,接收消息推送
UNSUBSCRIBE 取消已有的订阅
ACK 确认已成功消费消息,用于可靠投递
NACK 否定确认,通知 Broker 消息未正常消费
BEGIN 开启事务,后续消息进入事务上下文
COMMIT 提交事务,批量生效事务内的所有消息
ABORT 回滚事务,丢弃事务内的所有消息
DISCONNECT 主动断开连接,可附带回执保证优雅断开

2. 服务端命令

命令 作用
CONNECTED 连接成功响应,返回会话 ID、协商后的版本和心跳
MESSAGE 向订阅者推送的消息帧
RECEIPT 回执响应,对应客户端 receipt 头部请求,确认操作完成
ERROR 错误响应,连接失败、协议错误时返回,通常附带错误信息

五、关键工作机制

1. 连接建立流程

  1. 客户端发送 CONNECT 帧,携带支持的版本、认证信息、心跳参数
  2. Broker 校验通过后返回 CONNECTED 帧,确认协议版本、分配会话 ID
  3. 校验失败则返回 ERROR 帧并关闭连接

2. 消息确认机制

为保证消息可靠投递,STOMP 提供三级确认模式,订阅时通过 ack 头部指定:

  • auto(默认):自动确认,客户端收到消息即视为消费成功,无需手动 ACK
  • client:客户端批量确认,调用 ACK 时会确认该订阅下所有未确认的消息
  • client-individual:单条消息独立确认,每条消息都需要单独 ACK/NACK

3. 事务机制

通过 BEGIN / COMMIT / ABORT 实现消息的原子性批量操作:

  • 事务开启后,所有 SEND、ACK、NACK 都会进入事务上下文
  • 执行 COMMIT 后,所有操作一次性生效;执行 ABORT 则全部作废
  • 事务仅在当前会话内有效,连接断开自动回滚

4. 回执机制

客户端发送命令时可携带 receipt:id 头部,Broker 处理完成后会返回对应 ID 的 RECEIPT 帧,用于保证关键操作(如发送、断开)的可靠性。

5. 心跳保活

STOMP 1.1+ 支持心跳机制,连接时通过 heart-beat:cx,sx 协商:

  • cx:客户端期望服务端每 x 毫秒发一次心跳
  • sx:客户端每 x 毫秒向服务端发一次心跳
  • 心跳仅为单个换行符,不占用帧结构,用于检测连接断开、维持长连接

六、典型应用场景

1. WebSocket 实时通信(最主流场景)

原生 WebSocket 仅提供双向字节流,没有消息语义,需要自行设计格式、路由和订阅逻辑。STOMP 作为 WebSocket 子协议,可直接提供标准化的发布/订阅、消息路由、确认机制,是 Spring WebSocket 的默认方案,广泛用于:

  • 在线聊天室、即时通知
  • 实时数据大屏、股票行情推送
  • 协作编辑、状态同步

2. 跨语言消息队列接入

STOMP 客户端实现成本极低,脚本语言、前端 JS 等生态可以快速接入 ActiveMQ、RabbitMQ 等企业级消息中间件,无需复杂的二进制协议解析。

3. 轻量级微服务通信

对于不需要 AMQP 复杂路由能力的微服务场景,STOMP 可以作为轻量替代,实现服务间的异步解耦。

七、与同类协议对比

维度 STOMP AMQP MQTT 原生 WebSocket
协议类型 文本协议 二进制协议 二进制协议 传输层协议
设计目标 简单通用、易实现 企业级可靠消息 物联网低带宽 双向字节传输
消息语义 发布/订阅、队列 交换器、队列、路由、事务 发布/订阅、QoS 无,需自行实现
实现难度 极低,客户端几十行代码 高,协议复杂 较低 低,但上层逻辑需自研
调试成本 低,文本可读,telnet 可直连 高,需专用工具 低,但业务数据难解析
典型场景 Web实时通信、脚本语言接入 金融、企业级消息中间件 物联网、传感器 简单双向通信

八、主流实现

Broker 端

  • Apache ActiveMQ / ActiveMQ Artemis:原生完整支持 STOMP 全版本
  • RabbitMQ:通过 rabbitmq_stomp 插件支持
  • Spring Boot:内置简单 STOMP Broker,适合轻量 Web 场景
  • Apollo:高性能 STOMP 专用 Broker

客户端库

  • Java:Spring Messaging(Spring WebSocket 集成)
  • JavaScript:@stomp/stompjs(浏览器/Node.js 通用)、stomp.js
  • Python:stomp.py
  • Go、Ruby、C# 等语言均有成熟客户端实现

九、优缺点总结

优点

  1. 极简易用:类 HTTP 的文本格式,学习成本低,客户端开发速度快
  2. 调试友好:明文传输,可直接通过 telnet、wscat 等工具调试交互
  3. 传输层无关:可运行在 TCP、TLS、WebSocket 等任意可靠流之上
  4. 生态完善:几乎所有主流消息中间件和开发语言都支持
  5. 能力均衡:覆盖消息确认、事务、心跳等核心可靠能力,又不至于过于复杂

缺点

  1. 文本协议开销:相比二进制协议,相同 payload 下传输体积更大,性能略低
  2. 语义依赖 Broker:协议本身不定义队列、主题的具体行为,不同 Broker 实现可能有差异
  3. 高级特性不足:缺乏 AMQP 那样标准化的路由、死信、优先级等企业级特性
相关推荐
+VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue旅游管理系统(源码+数据库+文档)
java·开发语言·vue.js·spring boot·课程设计
需要8262 小时前
MySQL 索引 B+ 树与“查询为什么变慢了
java·spring boot·spring·spring cloud·tomcat
一 乐2 小时前
二手交易平台|基于springboot + vue二手交易平台(源码+数据库+文档)
java·数据库·vue.js·spring boot·小程序
万年咸鱼2 小时前
编译Java源程序
java
Wang's Blog2 小时前
Java 项目实战: 外卖平台-删除分类的关联校验与自定义业务异常
java·服务器·项目开发
hai_android2 小时前
Kotlin / Android 常用函数使用示例手册
android·java·kotlin
MayBaymax3 小时前
MongoDB 索引与事务
java·数据库·mongodb
vx-程序开发3 小时前
【计算机毕设】django校园跑腿服务系统83141
java·数据库·vue.js·spring boot·spring·elasticsearch·django
勇气要爆发3 小时前
006.注解
java·注解