扫描二维码

关注或者微信搜一搜:编程智域 前端至全栈交流与成长

发现1000+提升效率与开发的AI工具和实用程序https://tools.cmdragon.cn/


1. STOMP协议基础

STOMP(Simple Text Oriented Messaging Protocol)是一种基于文本的轻量级消息协议,常用于实现发布/订阅模式。与直接使用WebSocket相比,STOMP提供了更结构化的消息格式,支持以下核心功能:

  • 消息目的地(Destination):消息发送的目标地址(如"/topic/news")
  • 消息头(Headers):包含元数据的键值对(如消息类型、内容长度)
  • 消息体(Body):实际传输的数据内容(JSON/文本格式)

在FastAPI中实现STOMP协议的核心思路是通过WebSocket建立连接后,在消息处理层添加STOMP协议解析器。整个过程分为三个阶段:

  1. 客户端发送CONNECT帧建立STOMP会话
  2. 使用SUBSCRIBE命令订阅消息通道
  3. 通过SEND命令向指定目的地发送消息
graph TD
A[客户端] -->|WebSocket连接| B(FastAPI服务端)
B --> C{STOMP协议升级}
C -->|成功| D[消息路由器]
C -->|失败| E[关闭连接]
D --> F[订阅管理]
D --> G[消息转发]

2. FastAPI实现STOMP协议

以下示例代码演示了如何在FastAPI中实现STOMP协议支持:

# 环境依赖:fastapi==0.103.0 uvicorn==0.23.2 stomp.py==8.0.1
from fastapi import FastAPI, WebSocket
from stomp import parse_frame, Frame app = FastAPI() class StompManager:
def __init__(self):
self.subscriptions = {} async def handle_connect(self, frame, websocket):
# 协议版本验证
if frame.headers.get('accept-version') != '1.2':
await websocket.send_text('ERROR\nversion-not-supported\n\n')
return False
return True async def handle_subscribe(self, frame, websocket):
destination = frame.headers['destination']
sub_id = frame.headers['id']
self.subscriptions[sub_id] = {
'destination': destination,
'websocket': websocket
} @app.websocket("/stomp")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
manager = StompManager() try:
while True:
data = await websocket.receive_text()
frame = parse_frame(data) if frame.command == 'CONNECT':
if await manager.handle_connect(frame, websocket):
await websocket.send_text("CONNECTED\nversion:1.2\n\n")
elif frame.command == 'SUBSCRIBE':
await manager.handle_subscribe(frame, websocket)
elif frame.command == 'SEND':
# 消息路由逻辑
pass except Exception as e:
print(f"连接异常: {str(e)}")

代码解析:

  1. STOMP帧解析:使用stomp.py库的parse_frame方法解析原始消息
  2. 会话管理:通过StompManager类维护订阅关系
  3. 协议协商:在CONNECT阶段验证协议版本兼容性
  4. 订阅管理:使用字典存储订阅ID与WebSocket的映射关系

3. 最佳实践示例

实现消息广播功能的核心代码:

from typing import Dict
from fastapi import WebSocket
from pydantic import BaseModel class Subscription(BaseModel):
destination: str
websocket: WebSocket class MessageRouter:
def __init__(self):
self.channels: Dict[str, list] = {} async def add_subscriber(self, channel: str, websocket: WebSocket):
if channel not in self.channels:
self.channels[channel] = []
self.channels[channel].append(websocket) async def broadcast(self, channel: str, message: str):
for ws in self.channels.get(channel, []):
await ws.send_text(message) # 在SEND命令处理中调用
async def handle_send(frame, router: MessageRouter):
destination = frame.headers['destination']
await router.broadcast(destination, frame.body)

4. 课后Quiz

问题1:当客户端发送的STOMP协议版本不匹配时,服务端应该返回什么响应?

答案:服务端应返回ERROR帧,并在headers中包含version-not-supported错误码,立即关闭连接。

问题2:如何防止消息路由时的循环广播?

答案:在消息头中添加message-id字段,服务端维护已处理消息ID的缓存,对重复ID的消息直接丢弃。


5. 常见报错处理

报错1STOMP Protocol Error: Missing required header 'destination'

原因:SEND或SUBSCRIBE帧缺少destination头

解决方案

  1. 检查客户端代码是否正确设置destination
  2. 服务端添加头校验逻辑:
if 'destination' not in frame.headers:
await websocket.send_text('ERROR\nmissing-destination\n\n')

报错2WebSocket connection is already closed

原因:尝试向已关闭的连接发送消息

解决方案

# 发送前检查连接状态
for ws in list(self.channels[channel]):
if ws.client_state == WebSocketState.DISCONNECTED:
self.channels[channel].remove(ws)

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

,阅读完整的文章:如何在FastAPI中玩转STOMP协议升级,让你的消息传递更高效?

往期文章归档:

免费好用的热门在线工具

如何在FastAPI中玩转STOMP协议升级,让你的消息传递更高效?的更多相关文章

  1. 如何在.Net中使用Redis

    Redis是一个key-value存储系统.和Memcached类似,但是解决了断电后数据完全丢失的情况,而且她支持更多无化的value类型,除了和string外,还支持lists(链表).sets( ...

  2. 如何在MyBatis中优雅的使用枚举

    问题 在编码过程中,经常会遇到用某个数值来表示某种状态.类型或者阶段的情况,比如有这样一个枚举:   public enum ComputerState { OPEN(10), //开启 CLOSE( ...

  3. 如何在 Kubernetes 集群中玩转 Fluid + JuiceFS

    作者简介: 吕冬冬,云知声超算平台架构师, 负责大规模分布式机器学习平台架构设计与功能研发,负责深度学习算法应用的优化与 AI 模型加速.研究领域包括高性能计算.分布式文件存储.分布式缓存等. 朱唯唯 ...

  4. 如何在 Istio 中支持 Dubbo、Thrift、Redis 以及任何七层协议?

    赵化冰,腾讯云高级工程师,Istio Member,ServiceMesher管理委员,Istio 项目贡献者, Aerika 项目创建者 ,热衷于开源.网络和云计算.目前主要从事服务网格的开源和研发 ...

  5. springboot websocket集群(stomp协议)连接时候传递参数

    最近在公司项目中接到个需求.就是后台跟前端浏览器要保持长连接,后台主动往前台推数据. 网上查了下,websocket stomp协议处理这个很简单.尤其是跟springboot 集成. 但是由于开始是 ...

  6. 我是如何在SQLServer中处理每天四亿三千万记录的

    首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...

  7. 【转】我是如何在SQLServer中处理每天四亿三千万记录的

    原文转自:http://blog.jobbole.com/80395/ 首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文 ...

  8. 如何在SQLServer中处理每天四亿三千万记录

    首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...

  9. (转)我是如何在SQLServer中处理每天四亿三千万记录的

    首先声明,我只是个程序员,不是专业的DBA,以下这篇文章是从一个问题的解决过程去写的,而不是一开始就给大家一个正确的结果,如果文中有不对的地方,请各位数据库大牛给予指正,以便我能够更好的处理此次业务. ...

  10. 笔记整理--玩转robots协议

    玩转robots协议 -- 其他 -- IT技术博客大学习 -- 共学习 共进步! - Google Chrome (2013/7/14 20:24:07) 玩转robots协议 2013年2月8日北 ...

随机推荐

  1. Spring的三级缓存详解

    目录 1.什么是三级缓存 2.三级缓存详解 Bean实例化前 属性赋值/注入前 初始化后 总结 3.怎么解决的循环依赖 4.不用三级缓存不行吗 5.总结 一.什么是三级缓存 就是在Bean生成流程中保 ...

  2. 🎀SpringBoot启动创建系统托盘及功能

    简介 SpringBoot启动时,创建系统托盘,提供打开主程序及退出功能. 实现 启动类添加构造函数 public TjtoolApplication() { initUI(); } private ...

  3. Java线程控制: sleep、yield、join深度解析

    结论先行 sleep:主动让出CPU但保持锁,适合控制执行节奏和优化CPU占用 yield:建议让出CPU但无强制力,适用场景有限且效果不稳定 join:通过等待机制实现线程顺序控制,底层基于wait ...

  4. 基于主成分分析(PCA)的数据降维

    一.概述   主成分分析(Principal Component Analysis,PCA)是一种用于数据降维的方法,其核心目标是在尽可能保留原始数据信息的前提下,将高维数据映射到低维空间.该算法基于 ...

  5. 如何在 AI 小助手对话中显示原文预览

    写在前面 本文使用的开源工具平台包含以下内容: AI 助手平台:MaxKB 运维管理面板:1Panel Linux运维管理面板 一.整理原文链接 如果现有的文档已经有能够下载的链接或者预览链接,可以跳 ...

  6. Intel指令集及SIMD数据加速

    查看CPU相关信息 执行结果举例: 查看电脑CPU支持的指令集: cat /proc/cpuinfo | grep "processor" | wc -l 支持的指令集: 向量指令 ...

  7. React-Native开发鸿蒙NEXT-从global变量聊聊代码的内部优化

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  8. 鸿蒙版《智慧农业APP》通过华为云IoT平台实现软件硬件互联

    一.原理图 本篇不涉及硬件相关的功能开发,硬件设备使用MQTT客户端模拟,如果有硬件相关经验的可以直接使用真实硬件代替MQTT客户端. 1.华为云物联网服务器 华为云物联网平台是硬件设备端跟移动APP ...

  9. odoo14本地windows安装报错汇总

    odoo14安装libsass报错C++啥的解决办法:pip install wheel: pip install libsass-0.20.1-......whl 注意:whl版本应与python版 ...

  10. Golang相关环境变量

    GOROOT: GO语言的安装路径,linux系统下一般是/usr/local/go GOPATH: 程序员自己的go源码路径,比如开发一个Helloworld的项目,那么它的代码文件夹就应该放在GO ...