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 长连接的"服务器推" ...
随机推荐
- 看图认识CSS
教程: https://www.w3cschool.cn/css/ https://www.runoob.com/css/css-tutorial.html https://www.w3school. ...
- CSP-S模拟赛20241004
A 你考虑 可以把这个数组当中的每个数表示成另一种形式:\(a_i = k_i\times x+b\)(其中\(x\)是模数,\(b\)为余数). 对于求两个数是否对于某个余数同余,显然你要判断他们两 ...
- 基于Java+SpringBoot+Mysql实现的快递柜寄取快递系统功能实现八
一.前言介绍: 1.1 项目摘要 随着电子商务的迅猛发展和城市化进程的加快,快递业务量呈现出爆炸式增长的趋势.传统的快递寄取方式,如人工配送和定点领取,已经无法满足现代社会的快速.便捷需求.这些问题不 ...
- RK3568,字符设备框架:管理同主设备号、不同次设备号设备
字符设备框架:管理同主设备号.不同次设备号设备 以下代码针对迅为开发板RK3568,开发板系统是ubuntu20.04, 正文 以下是我写的字符设备框架,实现了管理同主设备号.不同次设备号的功能. 代 ...
- 鸿蒙NEXT开发案例:抛硬币
[1]引言(完整代码在最后面) 本项目旨在实现一个简单的"抛硬币"功能,用户可以通过点击屏幕上的地鼠图标来模拟抛硬币的过程.应用会记录并显示硬币正面(地鼠面)和反面(数字100面) ...
- Codeforces Round 988 (Div. 3)
Codeforces Round 988 (Div. 3) 总结 A 没啥好说的,用桶存出现次数. #include <iostream> #include <cstdio> ...
- 一个包含了 50+ C#/.NET编程技巧实战练习教程
DotNetExercises介绍 DotNetGuide专栏C#/.NET/.NET Core编程技巧练习集:C#/.NET/.NET Core编程常用语法.算法.技巧.中间件.类库.工作业务实操练 ...
- 项目监控之sentry
github: https://github.com/getsentry/sentry 1.什么是sentry? 当我们完成一个业务系统的上线时,总是要观察线上的运行情况,对于每一个项目,我们都没办法 ...
- GitBook之基本使用
GitBook 简介 GitBook 官网 GitBook 文档 GitBook 准备工作 安装 Node.js GitBook 是一个基于 Node.js 的命令行工具,下载安装 Node.js,安 ...
- kettle 使用 CARTE 执行
在执行KETTLE 任务的时候,可以使用本地执行,或者使用carte server执行. 1.启动carte server .\Carte.bat localhost 8080 2.配置子服务器 这里 ...