GPTBots使用fetch-event-source实现SSE POST传参

发布于:2025-06-17 ⋅ 阅读:(12) ⋅ 点赞:(0)

摘要:

SSE(Server-Sent Events)技术因其基于HTTP、原生支持以及实现简单的特点,非常适合大模型流式输出数据的场景,许多大模型厂商因此提供支持SSE的API。GPTBots也推出了支持SSE的对话API,近期对Web页面进行技术升级,SSE使用标准Event Source API被改造为基于fetch-event-source实现,从而支持POST请求传参。本文将围绕相关技术知识展开,进行对比分析并解析其原理。

一、什么是SSE

SSE(Server-Sent Events)是一种基于HTTP协议的服务器推送技术,允许服务器向客户端发送实时更新。它是HTML5标准的一部分,旨在提供一种轻量级的方式,使浏览器能够接收来自服务器的事件流。SSE的核心是EventSource接口,它为客户端提供了与服务器建立单向连接的能力,从而实现消息的实时传递。

SSE的工作原理非常简单:客户端通过HTTP请求向服务器发起连接,服务器在保持连接的同时,持续地以文本流的形式发送事件数据。客户端接收到数据后,可以通过JavaScript代码处理这些事件。

SSE的主要特点包括:

  • 单向通信:服务器可以主动向客户端推送数据,但客户端无法通过同一连接向服务器发送数据。

  • 自动重连:当连接意外断开时,浏览器会自动尝试重新连接。

  • 轻量级协议:基于HTTP协议,易于实现和调试。

  • 支持事件类型:支持自定义事件类型,便于对不同类型的数据流进行处理。

SSE非常适合大模型流式返回数据的场景,因此很多模型服务厂商提供了SSE的接口,前端接入后可以实现打字机效果,实时输出和展示大模型的回复内容。

二、SSE和WebSocket技术对比

SSE和WebSocket都是实现实时通信的技术,但它们的设计理念和适用场景存在显著差异。

特性

SSE

WebSocket

通信方向

单向(服务器 -> 客户端)

双向(客户端 <-> 服务器)

协议

基于HTTP协议

独立的WebSocket协议

连接数

每个客户端需要单独的HTTP连接

单个WebSocket连接支持双向通信

浏览器支持

原生支持,兼容性较好

需要浏览器支持WebSocket API

重连机制

内置自动重连

需要手动实现重连逻辑

数据格式

纯文本(UTF-8编码)

支持文本和二进制数据

实现复杂度

简单,基于HTTP

较复杂,需要独立的协议实现

适用场景

实时新闻、日志流、事件通知等

聊天应用、多人游戏、实时协作等复杂场景

选择SSE还是WebSocket,取决于具体的业务需求。如果只需要服务器向客户端推送数据,且对通信性能要求不高,SSE是一个简单高效的选择;而如果需要双向通信或对性能要求较高,WebSocket则更为适合。

三、标准的EventSource API

在浏览器中,SSE通过EventSource对象实现。以下是EventSource API的主要特性和用法:

1. 创建EventSource对象

使用EventSource对象时,需要指定服务器的URL:

const eventSource = new EventSource('https://example.com/sse');

2. 事件监听

EventSource支持三种事件类型:

  • message:处理默认事件。

  • open:连接成功时触发。

  • error:连接出错或断开时触发。

示例代码:

eventSource.onopen = function(event) {
  console.log('Connection opened:', event);
};

eventSource.onmessage = function(event) {
  console.log('Message received:', event.data);
};

eventSource.onerror = function(event) {
  console.error('Error occurred:', event);
};

3. 自定义事件类型

服务器可以发送自定义事件类型,客户端可以通过addEventListener监听:

eventSource.addEventListener('custom-event', function(event) {
  console.log('Custom event received:', event.data);
});

4. 关闭连接

可以通过调用close()方法手动关闭连接:

eventSource.close();
console.log('Connection closed');

5. 服务器发送数据格式

服务器需要按照以下格式发送数据:

data: Hello, World!
event: custom-event
id: 12345
retry: 3000
  • data:事件数据。

  • event:事件类型(可选)。

  • id:事件ID,用于断线重连时恢复状态(可选)。

  • retry:指定重连间隔时间(以毫秒为单位,可选)。

四、@microsoft/fetch-event-source 介绍

@microsoft/fetch-event-source是微软开发的一个轻量级库,用于在Node.js和浏览器环境中实现SSE(Server-Sent Events)。与原生的EventSource相比,它提供了更多的灵活性和功能,例如支持自定义HTTP方法(如POST)、请求头、认证、请求体等。

npm仓库:@microsoft/fetch-event-source - npm

1. 安装

可以通过npm或yarn安装:

npm install @microsoft/fetch-event-source

2. 使用示例

以下是一个简单的使用示例:

import { fetchEventSource } from '@microsoft/fetch-event-source';

fetchEventSource('https://example.com/sse', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer YOUR_TOKEN',
  },
  body: JSON.stringify({ key: 'value' }),
  onopen(response) {
    if (response.ok && response.headers.get('content-type') === 'text/event-stream') {
      console.log('Connection established');
    } else {
      console.error('Connection failed');
    }
  },
  onmessage(event) {
    console.log('Message received:', event.data);
  },
  onclose() {
    console.log('Connection closed by server');
  },
  onerror(err) {
    console.error('Error occurred:', err);
  },
});

3. 特性

  • 支持自定义HTTP方法(如POST)。

  • 支持请求头和请求体。

  • 提供事件钩子(如onopenonmessageoncloseonerror)。

  • 支持断线重连。

五、@microsoft/fetch-event-source 原理解析

@microsoft/fetch-event-source的实现基于fetch API,通过流式处理实现了SSE的功能。以下是其核心实现原理的解析:

1. 核心逻辑

该库的核心逻辑是使用fetch API发起HTTP请求,并通过ReadableStream解析服务器返回的事件流。

源码片段(简化版):

async function fetchEventSource(url, options) {
  const response = await fetch(url, options);
  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  let buffer = '';
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop(); // 保留未完整的行

    for (const line of lines) {
      if (line.startsWith('data:')) {
        const data = line.slice(5).trim();
        options.onmessage({ data });
      }
    }
  }

  options.onclose();
}

2. POST传参的实现

与原生EventSource不同,该库允许通过POST方法发送参数。实现方式是将请求体传递给fetch API:

fetch(url, {
  method: 'POST',
  headers: options.headers,
  body: options.body,
});

3. 自动重连

当连接断开时,库会自动尝试重新连接:

setTimeout(() => {
  fetchEventSource(url, options);
}, retryInterval);

4. 错误处理

通过try-catch捕获错误,并调用onerror回调:

try {
  // 读取流数据
} catch (err) {
  options.onerror(err);
}

网站公告

今日签到

点亮在社区的每一天
去签到