Event-Stream技术
服务端
- websocket和event-stream的优缺点
WebSocket和Event-Stream(Server-Sent Events)都是实现实时通信的技术,但是它们各自有不同的优缺点。
️ WebSocket
- 优点:
- 双向通信:WebSocket提供了一个全双工的通信通道,客户端和服务器可以同时发送和接收数据。
- 实时性:由于WebSocket是持久连接,所以它具有高实时性。
- 更少的数据传输量:WebSocket在建立连接后,数据传输时不需要包含HTTP头,因此数据传输量较小。
- websocket可传输较为复杂的数据结构,例如json、二进制字节等。
- websocket针对java、Python等语言支持较好
- websocket天然支持跨域问题(据说也有跨域问题,目前无法模拟出来)
- 缺点:
- 虽然大部分现代浏览器都支持WebSocket,但是一些老版本的浏览器可能不支持。
- 协议复杂:WebSocket的协议相对复杂,需要处理连接、断开连接、心跳等问题。
- 适用场景
- 适合较为复杂的业务场景,需要多次进行通讯,例如:聊天、游戏等
Event-Stream (Server-Sent Events):
- 优点:
- 简单易用:Event-Stream的API相对简单,易于使用和理解。
- 自动重连:如果连接断开,Event-Stream会自动尝试重连。
- 基于HTTP:Event-Stream基于HTTP协议,因此可以利用现有的HTTP基础设施,如负载均衡和缓存。
- 缺点:
- 单向通信:Event-Stream只支持服务器向客户端发送数据,不支持客户端向服务器发送数据。
- 实时性:由于Event-Stream是基于HTTP的,因此它的实时性可能不如WebSocket。
- 数据传输量:Event-Stream在每次发送数据时都需要包含HTTP头,因此数据传输量可能较大。
- 数据结构:Event-Stream传输仅仅支持字符形式,无法适应较复杂的场景
- java流式下发可能出现丢包、站包问题,需要自己实现编解码来对消息进一步处理
- 适用场景
- 适合较为简单的场景,例如:大模型客户端发一次消息后,服务端返回结果
event-stream形式
JAVA
- java实现SSE的方式主要有2种,即通过Spring mvc提供的SseEmitter和Flux。目前我用的比较多的是SseEmitter(原因:本人比较懒,此方式较为简单)
- 只需定义一个
SseEmitter对象并输出即可,通过SseEmitter.send()发送消息(发送消息需要异步执行)- SseEmitter构造函数中,超时时间设置为0,否则请求过长,会出现超时情况(默认超时时间和http接口相同,可通过spring配置进行设置)
- SseEmitter种主要的方法
- send:发送消息
- complete():表示消息已结束
- completeWithError(): 发送错误并结束,多用于异常捕获中
@GetMapping(value = "sseEmitterTest")
public Object sseEmitterTest(@RequestParam(value = "name") String name) {
SseEmitter sseEmitter = new SseEmitter(0L);
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 50, 60L, TimeUnit.SECONDS, queue);
threadPoolExecutor.execute(() -> {
char[] charArray = name.toCharArray();
for (char charStr : charArray) {
try {
sseEmitter.send(new String(new char[]{charStr}));
Thread.sleep(100);
} catch (IOException | InterruptedException e) {
sseEmitter.completeWithError(e);
}
}
sseEmitter.complete();
});
return sseEmitter;
}
客户端
JAVA
引入依赖
<dependency>
<groupId>org.asynchttpclient</groupId>
<artifactId>async-http-client</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>3.5.2</version>
</dependency>
调用接口
消息处理类
public class DefaultMessageHandler implements AsyncHandler<Response> {
@Override
public State onStatusReceived(HttpResponseStatus httpResponseStatus) {
return null;
}
@Override
public State onHeadersReceived(HttpHeaders httpHeaders) {
return null;
}
@Override
public State onBodyPartReceived(HttpResponseBodyPart httpResponseBodyPart) {
// 业务逻辑处理
return State.CONTINUE;
}
@Override
public void onThrowable(Throwable throwable) {
}
@Override
public Response onCompleted() {
return null;
}
}
主方法
@NoArgsConstructor
public class HttpStreamClient {
private AsyncHandler<Response> asyncHandler;
public HttpStreamClient(AsyncHandler<Response> asyncHandler) {
this.asyncHandler = asyncHandler;
}
public void sendMessage(String url, String message) {
// 组装okhttp请求
AsyncHttpClient client = Dsl.asyncHttpClient();
BoundRequestBuilder requestBuilder = client.preparePost(url);
requestBuilder.setHeader("Accept", "text/event-stream");
requestBuilder.setHeader("Content-Type", "application/json");
requestBuilder.setBody(message);
requestBuilder.execute(asyncHandler);
}
public static void main(String[] args) {
DefaultMessageHandler defaultMessageHandler = new DefaultMessageHandler();
HttpStreamClient httpStreamClient = new HttpStreamClient(defaultMessageHandler);
String message = "Hello WOrld!"
httpStreamClient.sendMessage("API", message);
}
}
Python
引入依赖
pip install requests
编码部分
import requests
import json
def invokeStreamLlm():
requestBody = {
name: "Hello World!"
}
response = requests.post(
"API",
json=requestBody,
stream=True,
headers={"Content-Type": "application/json"},
)
if response.status_code != 200:
return
for line in response.iter_lines():
if line and line.strip():
content = json.loads(line[5:])
code = content['code']
if code == 200:
print(content['data'])
elif code == -200:
print('结束标识')
if __name__ == "__main__":
content = invokeStreamLlm()
vue
- 本地开发时,通过vue的正向代理,流式接口无法做到流式下发。数据会在最后一块全部下发
- 本地想要流式下发解决方法:
- 本地部署一个nginx,通过nginx反向代理接口后,可实现流式下发
- 注:实际项目中,url则是vue配置的api,ip和端口采用代理来代替
引入依赖
npm install @microsoft/fetch-event-source -D
编码部分
- penWhenHidden表示是否监听窗口变化,为true表示不见听窗口变化,集焦点离开窗口时,不自动断开重连
- ctrl:
- 由于sse接口存在断开重连机制,可能存在多次 调用的情况
- 通过ctrl控制器,可以控制关闭客户端,不会再进行重连
<script>
import { fetchEventSource } from '@microsoft/fetch-event-source';
export default {
data() {
return {
ctrl: new AbortController(),
};
},
mounted() {
this.invokeSse();
},
methods: {
invokeSse() {
const that = this;
fetchEventSource('API', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: ['text/event-stream', 'application/json'],
},
body: JSON.stringify({
data: ''
}),
penWhenHidden: true,
signal: that.ctrl.signal,
onopen(event) {
console.log(event);
},
onmessage(msg) {
// 消息接收
console.log(msg);
},
onclose(e) {
console.log(e);
that.ctrl.abort();
},
onerror(err) {
console.log(err);
that.ctrl.abort();
},
});
}
},
};
</script>
Event-Stream技术的更多相关文章
- Azure Event Hub 技术研究系列2-发送事件到Event Hub
上篇博文中,我们介绍了Azure Event Hub的一些基本概念和架构: Azure Event Hub 技术研究系列1-Event Hub入门篇 本篇文章中,我们继续深入研究,了解Azure Ev ...
- Azure Event Hub 技术研究系列3-Event Hub接收事件
上篇博文中,我们通过编程的方式介绍了如何将事件消息发送到Azure Event Hub: Azure Event Hub 技术研究系列2-发送事件到Event Hub 本篇文章中,我们继续:从Even ...
- [Reactive Programming] Using an event stream of double clicks -- buffer()
See a practical example of reactive programming in JavaScript and the DOM. Learn how to detect doubl ...
- Azure Event Bus 技术研究系列1-Event Hub入门篇
前两个系列研究了Azure IoT Hub和Azure Messaging.最近准备继续研究Azure Event Bus,即Azure的事件中心.首先, Azure Event Hub的官方介绍: ...
- Azure Event Hub 技术研究系列1-Event Hub入门篇
前两个系列研究了Azure IoT Hub和Azure Messaging.最近准备继续研究Azure Event Hub,即Azure的事件中心.首先, Azure Event Hub的官方介绍: ...
- Event Logging 技术简介
https://blog.csdn.net/xiliang_pan/article/details/41805023
- Azure IoT Hub和Event Hub相关的技术系列-索引篇
Azure IoT Hub和Event Hub相关的技术系列,最近已经整理了不少了,统一做一个索引链接,置顶. Azure IoT 技术研究系列1-入门篇 Azure IoT 技术研究系列2-设备注册 ...
- (ETW) Event Tracing for Windows 入门 (含pdf下载)
内容提纲 • ETW 介绍 • ETW 使用 • ETW 监控本机Demo • ETW 监控远程机器的思路 • 底层类库:EventSource 介绍 • 底层类库:TraceEvent 介绍 ETW ...
- HTML5中的服务器‘推送’技术 -Server-Sent Events
转帖:http://www.developersky.net/thread-63-1-1.html 一直以来,HTTP协议都是严格遵循Request-Response模型的.客户端发送一个Reques ...
- “服务器推”技术【转载+整理】
原文地址 本文内容 "服务器推(server-push)"技术的应用 基于客户端套接口的"服务器推"技术 基于 HTTP 长连接的"服务器推" ...
随机推荐
- bresenham算法(贝汉明算法)
- Sql高级
sql高级 1. 索引与视图 常见的数据结构 栈:先进后出 队列:先进先出 数组:查询快,根据下标查询 链表:分为双链表与单链表.单链表指向下一个数据的存储位置:双链表指向前一个与下一个数据的存储位置 ...
- .NET周刊【10月第4期 2024-10-27】
国内文章 C#实现信创国产Linux麦克风摄像头推流(源码,银河麒麟.统信UOS) https://www.cnblogs.com/shawshank/p/18494362 随着国际形势变化,软件信创 ...
- spring boot中使用quratz实现定时。 使用task直接调用的实现方法
1.定义工作类 2.创建配置类,将工作对象绑定到工作明细,然后创建触发器 与工作明细进行绑定 二.使用task实现定时任务 1.启动类上开启定时功能 2.在需要定时的任务上增加Schedule注解,并 ...
- mac 系统使用vscode 创建c/c++ 工程项目 并配置断点调试
mac 使用vsCode 创建c/c++ 工程项目 并配置断点调试 使用vscode 创建c/c++工程项目 准备工作 使用 vscode 下载插件 C/C++ Project Generator 开 ...
- spring注解@PostConstruct
该注解可以实现在运行工程时,自动运行该注解下的方法: @PostConstruct是java5的时候引入的注解,指的是在项目启动的时候执行这个方法,也可以理解为在spring容器启动的时候执行,可作为 ...
- win10本地客户端配置SSL并使用MQTTX
1. 本地下载Openssl(默认安装即可,最后一个将打赏取消勾选) Win32/Win64 OpenSSL Installer for Windows - Shining Light Pro ...
- NZOJ 模拟赛5
T1 逃离遗迹 根据外星人的回信,在遗迹中有分布着三样道具.当三样道具都拿走后,遗迹就很快自动毁灭,所以必须要在最短时间内离开.遗迹可以看作是由N个房间(编号1..N)和N-1条长度不等通道所组成,并 ...
- 自定义 MySQL Shell 提示符
MySQL Shell 中的提示符的样式和格式可以根据使用者的需求进行定制.我们可以配置提示符以显示有关数据库连接和使用的模式的不同或简化信息.本文将展示如何添加视觉提示,让您知道何时连接到生产数据库 ...
- python图形界面开发工具之PySimpleGUI
缘起: 工作中使用频次较高的操作都需要登录到某个管理平台上进行选择操作,如果是给别人使用还算可以, 但是作为平常使用还是感觉较为繁琐,于是打算开发一个桌面小工具解决这个痛点,达到使用时及时调起使用,方 ...