前端技术大放送,SSE 流式传输全攻略

5 阅读3分钟

探索前端新境界:SSE 流式传输的魅力

在前端开发的浩瀚宇宙中,总有一些技术如璀璨星辰,吸引着我们不断探索。今天,就让我们一同走进 SSE 流式传输的世界,感受它的独特魅力。

一、初遇 SSE

你还记得在使用某些智能应用,如 DeepSeek 时,输入问题后,答案仿佛具有魔法,能一点点地呈现在页面上吗?起初,我猜测这可能是 WebSocket 的神奇推送,但经过仔细检查网络请求,我发现并非如此,而是一种基于 HTTP 的特殊技术 —— SSE(Server-Sent Events)。

与 WebSocket 不同,SSE 并非基于 TCP 协议,而是依附于 HTTP 协议。它是一种单工通信模式,专为服务端向浏览器端实时推送消息而生。虽然功能相对有限,但却以其简洁轻便、易于实现而备受青睐。

二、SSE 与 WebSocket 的对比

为了更清晰地理解 SSE 的特点,让我们把它和 WebSocket 放在一起比较一番:

特性SSEWebSocket
基础协议HTTP 协议TCP 协议
通信模式单工(服务端到浏览器)全双工(可双向通信)
复杂程度轻量级,简单易用相对复杂
断线重连内置断线重连功能需手动实现
消息类型文本或经 Base64、gzip 处理的二进制消息支持多种类型消息
自定义事件支持自定义事件类型不支持自定义事件类型
连接数量HTTP/1.1 最多 6 个,HTTP/2 默认 100 个无限制

从表中可见,若项目需求仅为服务端向浏览器端推送消息,且希望快速实现,SSE 当然是更优之选。

三、浏览器中的 SSE API

在浏览器端,我们主要借助 EventSource API 来与 SSE 服务器进行交互。

  1. 1. 建立连接 :通过 new EventSource(url) 创建实例,其中 url 为服务器端提供的接口地址。还可以传入可选的 options 参数,如 {withCredentials: true} ,用于处理跨域凭据问题。
  2. 2. 监听事件 :EventSource 实例提供了多种事件供我们监听,包括 onopen (连接建立)、onmessage (接收到消息)、onerror (出现错误)。除了系统预设事件,还能自定义事件类型,只需在服务器端指定事件名称即可。

四、实战封装 SSEService 类

为了方便在项目中使用 SSE,我们可以对其进行封装,创建一个 SSEService 类。

class SSEService {
    constructor() {
        this.eventSource = null;
        this.isClosing = false;
    }
    connect(url, options = {}) {
        if (this.eventSource) {
            this.disconnect();
        }
        this.eventSource = new EventSource(url);
        // 连接打开时的处理
        this.eventSource.onopen = () => {
            console.log('SSE 连接已建立');
            this.isClosing = false;
            if (options.onOpen) {
                options.onOpen();
            }
        };
        // 接收到消息时的处理
        this.eventSource.onmessage = event => {
            try {
                const data = JSON.parse(event.data);
                if (options.onMessage) {
                    options.onMessage(data);
                }
                // 假设 status 为 1 表示最后一条消息
                if (data.status === 1) {
                    this.isClosing = true;
                    this.disconnect();
                }
            } catch (error) {
                console.error('解析 SSE 消息失败:', error);
            }
        };
        // 出现错误时的处理
        this.eventSource.onerror = error => {
            if (this.isClosing) {
                return;
            }
            console.error('SSE 连接错误:', error, new Date().toLocaleString());
            if (options.onError) {
                options.onError(error);
            }
            this.disconnect();
        };
    }
    // 断开连接
    disconnect() {
        if (this.eventSource) {
            this.eventSource.close();
            this.eventSource = null;
            console.log('SSE 连接已关闭', new Date().toLocaleString());
        }
    }
}
export default SSEService;

在实际使用时,只需创建该类的实例,调用 connect 方法传入相应的 url 和回调函数即可。

const sseService = new SSEService();
const url = `/api/stream?query=${encodeURIComponent(query)}`;
sseService.connect(url, {
    onMessagedata => {
        // 在此处处理接收到的数据,如更新页面显示
        console.log('收到数据:', data);
    },
    onError() => {
        // 处理连接错误情况
        console.error('连接出错');
    }
});

五、应对流式传输的“小插曲”

在开发过程中,有时会遇到使用 webpack 打包后,流式传输效果不理想的情况 —— 本应逐步显示的数据却等到全部接收完后才一次性呈现。不用担心,这通常是因为 webpack 的代理服务器配置中 compress 设置为 true 导致的。只需将其改为 false,即可恢复正常的流式传输效果。

总之,SSE 流式传输技术在特定场景下能为我们带来流畅、实时的用户体验,其简洁的实现方式也为前端开发增添了一份便利。希望本文能帮助你开启 SSE 的精彩之旅,让前端应用更具活力。