@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) || {}ctrl.abort()callData(data)} 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 monkeymonkey.patch_all()import timefrom flask import Response, stream_with_context
from flask import Flask
from gevent.pywsgi import WSGIServer
from flask import requestapp = Flask(__name__)def predict():chatbot = [""]mid = """一、引言\n1. 背景介绍\n2. 研究意义\n\n二、多旋翼无人机概述\n1. 多旋翼无人机的定义\n2. 多旋翼无人机的特点\n3. 多旋翼无人机的基本结构\n\n三、多旋翼无人机控制方法\n1. 手动控制\n2. 遥控控制\n3. 自主控制\n\n四、多旋翼无人机调度方法\n1. 手动调度\n2. 遥控调度\n3. 自主调度\n\n五、多旋翼无人机应用实例\n1. 农业领域\n2. 航拍领域\n3. 搜索救援\n4. 其他应用领域\n\n六、多旋翼无人机的安全问题\n1. 飞行安全隐患\n2. 数据隐私问题\n3. 人机交互问题\n\n七、结论\n1. 研究总结\n2. 研究局限\n3. 研究展望"""s = ""for response in mid:s += responseyield [s], []@app.route("/api/stream", methods=["GET", "POST"])
def progress():@stream_with_contextdef generate():ratio = 1data_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,}},