扫描二维码

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

发现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. ReadWriteLock:读写锁

    一. /* * 1. ReadWriteLock : 读写锁 * * 写写/读写 需要"互斥" * 读读 不需要互斥 * */ public class TestReadWrite ...

  2. js判断对象任意深度的key属性是否存在,js的iset方法

    ​ 方法一: 支持纯对象的obj // isset.js module.exports = (obj, keyPath) => { const keys = keyPath.split('.') ...

  3. Windows路径或者Linux路径映射成web路径进行访问代码

    package com.soft.mpms.zframe.config; import java.io.File; import org.springframework.context.annotat ...

  4. 一、C语言概述

    声明 本文内容大多取自<高级语言程序设计一书>,为本人学习笔记记录,切勿用于商业用途. 第一节 计算机发展 电子计算机已经历的四个发展时代: 第一代:20 世纪 50 年代,主要采用真空电 ...

  5. 解锁UV工具新玩法:让Python脚本运行更高效的实用技巧

    作为Python开发者,你是否经常被依赖安装的漫长等待.虚拟环境的繁琐管理,或是脚本分享时"环境不一致"的问题困扰? 近年来,一款名为UV的工具悄然兴起,它不仅以极速安装依赖著称, ...

  6. K8s新手系列之ReplicaSet资源

    概述 官网地址:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/replicaset/ ReplicaSet简称rs,其 ...

  7. 【语义分割专栏】先导篇:评价指标(PA,CPA,IoU,mIoU,FWIoU,F1)

    目录 前言 混淆矩阵 计算混淆矩阵 评价指标 像素准确率(Pixel Accuracy,PA) 类别像素准确率(Class Pixel Accuracy,CPA) 类别平均像素准确率(Mean Pix ...

  8. C# 利用反射模拟多态效果

    public class A { } public class B : A { } public class C : A { } public static class Extension { pub ...

  9. PC端自动化测试实战教程-6-pywinauto 打印和保存控件菜单树结构之ElementNotFoundError(详细教程)

    1.简介 其实前边的文章宏哥已经在控制台打印过控件菜单树结构,只是没有将其保存到文件中.只需要一个方法即可.在pywinauto中可以使用 print_control_identifiers() 方法 ...

  10. 卷积神经网络(CNN)模型

    一.概述   卷积神经网络(Convolutional Neural Network, CNN)是一种深度学习模型,广泛应用于图像识别.计算机视觉等领域.其设计理念源于对生物视觉皮层神经机制的模拟,核 ...