@microsoft/fetch-event-source
是一个由微软提供的库,用于在客户端和服务器之间建立基于 EventSource 的连接。EventSource 是一种 HTTP 协议,允许服务器向客户端推送实时事件流。该库提供了对 EventSource 协议的封装,使得在前端 JavaScript 中使用 EventSource 变得更加方便。在
@microsoft/fetch-event-source
中,主要使用fetchEventSource
函数来创建一个新的 EventSource 连接。这个函数接受一个 URL 参数,以及一个配置对象,其中可以包含一些选项,如请求方法、请求头、请求体等。当服务器向客户端推送事件时,可以通过onmessage
回调函数来处理这些事件。此外,还可以提供onerror
和onclose
回调函数来处理连接错误和关闭事件
一、安装
pnpm install @microsoft/fetch-event-source
二、使用
前端vue3:
import { fetchEventSource } from '@microsoft/fetch-event-source'
class RetriableError extends Error {}
class FatalError extends Error {}
const EventStreamContentType = 'text/event-stream; charset=utf-8'
export const fetchEventGpt = (data: any, callData: (arg0: any) => void) => {
const ctrl = new AbortController()
fetchEventSource('/api/stream', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
signal: ctrl.signal,
openWhenHidden: true,
async onopen(response: any) {
// 成功连接时回调
if (response.ok && response.headers.get('content-type') === EventStreamContentType) {
return // everything's good
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
// client-side errors are usually non-retriable:
throw new FatalError()
} else {
throw new RetriableError()
}
},
onmessage(msg: { data: any; event: string }) {
// 服务器返回消息回调 返回{ data,event,id,retry } ,data即服务器返回数据
// if the server emits an error message, throw an exception
// so it gets handled by the onerror callback below:
if (msg.event === 'FatalError') {
throw new FatalError(msg.data)
}
if (msg.event == '') {
// 进行连接正常的操作
try {
const data = JSON.parse(msg.data)?? {}
const {finish, code } = data??{}
callData(data)
if(code*1 === 200 && finish) {
ctrl.abort()
}
} catch (err) {
console.log(err)
throw err
}
}
if (msg.event === 'close') {
ctrl.abort()
}
},
onclose() {
// 正常结束的回调
ctrl?.abort()
throw new RetriableError()
},
onerror(err: any) {
// 连接出现异常回调
// 必须抛出错误才会停止
ctrl?.abort()
if (err instanceof FatalError) {
throw err // rethrow to stop the operation
} else {
// do nothing to automatically retry. You can also
// return a specific retry interval here.
}
},
})
}
服务端python:
from gevent import monkey
monkey.patch_all()
import time
from flask import Response, stream_with_context
from flask import Flask
from gevent.pywsgi import WSGIServer
from flask import request
app = Flask(__name__)
def predict():
chatbot = [""]
mid = """
一、引言\n1. 背景介绍\n2. 研究意义\n\n二、多旋翼无人机概述\n
1. 多旋翼无人机的定义\n2. 多旋翼无人机的特点\n3. 多旋翼无人机的基本结构\n\n
三、多旋翼无人机控制方法\n1. 手动控制\n2. 遥控控制\n3. 自主控制\n\n
四、多旋翼无人机调度方法\n1. 手动调度\n2. 遥控调度\n3. 自主调度\n\n
五、多旋翼无人机应用实例\n1. 农业领域\n2. 航拍领域\n3. 搜索救援\n
4. 其他应用领域\n\n六、多旋翼无人机的安全问题\n1. 飞行安全隐患\n
2. 数据隐私问题\n3. 人机交互问题\n\n七、结论\n1. 研究总结\n2. 研究局限\n3. 研究展望
"""
s = ""
for response in mid:
s += response
yield [s], []
@app.route("/api/stream", methods=["GET", "POST"])
def progress():
@stream_with_context
def generate():
ratio = 1
data_stream = predict()
for data in data_stream:
yield str("data:") + str(data) + "\n\n"
print("ratio:", ratio)
time.sleep(0.1)
headers = {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"X-Accel-Buffering": "no",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,POST",
"Access-Control-Allow-Headers": "x-requested-with,content-type",
}
return Response(generate(), mimetype="text/event-stream", headers=headers)
if __name__ == "__main__":
http_server = WSGIServer(("0.0.0.0", int(8081)), app)
http_server.serve_forever()
我们创建了一个指向 http://192.168.4.164:8081/gptchat/gpt
的 EventSource 连接,使用 POST 方法发送 JSON 格式的请求体数据。当接收到服务器推送的事件时,会打印事件数据。如果发生错误或连接关闭,也会打印相应的信息。
需要注意的是,虽然 EventSource 本身不支持 POST 方法,但通过使用 fetchEventSource
函数和适当的配置,我们可以模拟 POST 请求的效果。在服务器端,需要正确处理这种 POST 请求,并返回正确格式的事件流数据。
此外,由于 EventSource 是基于 HTTP 的协议,因此它只能在支持 HTTP 的环境中使用,如浏览器端或 Node.js 服务器端。同时,由于它是基于长连接的协议,因此在使用过程中需要注意连接的管理和错误处理。
三、遇到问题
1、跨域问题
设置mode: "no-cors" 解决跨域问题,但是返回的body信息为null
在vite.config.ts配置代理
devServer: {
port: 8089,
proxy: {
"/api": {
target: "http://192.168.4.164:8081",
changeOrigin: true,
}
},