本文最后更新于 2025-03-30,文章超过7天没更新,应该是已完结了~

1. 什么是 EventSource

EventSource 是一种服务器发送事件(Server-Sent Events, SSE)的工具或接口,常用于从服务器向客户端推送实时更新数据。这种机制适用于需要轻量级、单向通信的场景。

2. 基础概念

  1. 服务器发送事件(SSE):

    • 是一种HTTP 长连接机制,允许服务器通过持续的连接推送数据给客户端。

    • 使用了简单的 HTTP 协议而非 WebSocket,所以无需复杂的握手或协议切换。

  2. 特点:

    • 单向通信:服务器推送数据,客户端接收,不能反向发送数据。

    • 自动重连:当连接断开时,浏览器或客户端会自动尝试重新连接。

    • 轻量级:相比 WebSocket 更加轻量,适用于事件更新、通知等。

  3. 适用场景:

    • 实时数据更新:股票行情、天气更新等。

    • 通知推送:系统通知、消息提醒。

    • 流式输出:日志实时显示、大文件下载进度等。


2. EventSource 工具的作用

在 Java 中,EventSource 是一个接口,它定义了 SSE 的核心功能,负责管理与服务器的事件流通信。

主要功能:

  1. 建立连接: 使用底层的 HTTP 客户端发起长连接请求(如 OkHttpClient)。

  2. 监听事件: 通过 EventSourceListener 接口接收服务端推送的事件数据。

  3. 管理连接生命周期: 支持手动关闭连接或在发生错误时进行处理。

3. EventSource 的核心接口

(1)EventSource

EventSource 是核心接口,定义了事件流的基本操作。

public interface EventSource {
    /**
     * 获取当前事件源的请求
     */
    Request request();

    /**
     * 取消当前事件流,关闭连接
     */
    void cancel();

    /**
     * 工厂接口,用于创建事件源
     */
    interface Factory {
        /**
         * 创建新的事件源
         * @param request HTTP 请求
         * @param listener 事件监听器
         * @return 事件源
         */
        EventSource newEventSource(Request request, EventSourceListener listener);
    }
}
(2)EventSourceListener

EventSourceListener 是事件流的监听接口,处理服务端推送的事件数据和连接状态。

public interface EventSourceListener {
    /**
     * 接收到事件数据
     */
    void onEvent(EventSource eventSource, @Nullable String id, @Nullable String type, String data);

    /**
     * 连接关闭时调用
     */
    void onClosed(EventSource eventSource);

    /**
     * 连接失败或发生错误时调用
     */
    void onFailure(EventSource eventSource, @Nullable Throwable t, @Nullable Response response);
}
(3)EventSources 工厂

EventSources 是一个工具类,提供创建 EventSource.Factory 的方法。

public final class EventSources {
    public static EventSource.Factory createFactory(OkHttpClient client) {
        return new EventSource.Factory() {
            @Override
            public EventSource newEventSource(Request request, EventSourceListener listener) {
                RealEventSource realEventSource = new RealEventSource(request, listener);
                realEventSource.connect(client);
                return realEventSource;
            }
        };
    }
}

为什么使用相似的名字?

使用相似的名字是为了表达两者之间的关联性,同时保持语义清晰。

  1. 语义上的一致性:

    • EventSource 是核心接口,表示一个事件流。

    • EventSources 是工具类,用于操作 EventSource 或创建工厂。

    • 这种命名方式直观地传达了 EventSources 是围绕 EventSource 的辅助类。

  2. 单一职责原则:

    • EventSource 专注于定义事件流的行为。

    • EventSources 专注于提供与事件流相关的辅助方法。

    • 两者职责分明但紧密相关,使用类似名字是合理的。

  3. 命名惯例: 在 Java 中,类似的命名方式很常见:

    • Collections(工具类) vs Collection(接口)。

    • Executors(工具类) vs Executor(接口)。

    • Streams(工具类) vs Stream(接口)。

4. EventSource 的用法

(1)基础用法示例

以下是一个完整的使用示例,展示如何创建和使用 EventSource

import okhttp3.*;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSourceListener;
import okhttp3.sse.EventSources;

import java.util.concurrent.TimeUnit;

public class EventSourceExample {
    public static void main(String[] args) {
        // 创建 OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(0, TimeUnit.MILLISECONDS) // SSE 长连接无超时
                .build();

        // 创建 EventSource 工厂
        EventSource.Factory factory = EventSources.createFactory(client);

        // 构建请求
        Request request = new Request.Builder()
                .url("https://example.com/sse")  // 服务器 SSE 地址
                .build();

        // 创建事件源
        factory.newEventSource(request, new EventSourceListener() {
            @Override
            public void onEvent(EventSource eventSource, String id, String type, String data) {
                System.out.println("接收到事件:类型 = " + type + ",数据 = " + data);
            }

            @Override
            public void onClosed(EventSource eventSource) {
                System.out.println("事件源已关闭");
            }

            @Override
            public void onFailure(EventSource eventSource, Throwable t, Response response) {
                System.err.println("事件源错误:" + t.getMessage());
            }
        });
    }
}

5. 核心概念和机制

(1)Server-Sent Events (SSE)
  • 协议: 基于 HTTP,使用 text/event-stream 内容类型。

格式: 服务端推送的事件以纯文本方式发送,格式如下:

id: 1
event: message
data: {"message": "Hello World"}
(2)EventSource 工厂模式
  • 使用 EventSource.Factory 隔离具体实现。

  • 提供统一的创建方式,便于扩展和管理。

(3)连接生命周期
  • 事件源在以下情况下终止连接:

    1. 服务端主动关闭连接。

    2. 客户端调用 EventSource.cancel()

    3. 发生网络异常或超时。

(4)自动重连
  • 如果需要自动重连,可以在 onFailure 回调中重新调用 newEventSource

6. 与 WebSocket 的对比

特性

SSE

WebSocket

通信方向

单向(服务器 → 客户端)

双向通信

协议复杂性

使用 HTTP 协议

使用 WebSocket 协议

连接方式

简单 HTTP 长连接

TCP 协议,需握手切换协议

重连机制

自动重连,浏览器原生支持

需要客户端手动实现

数据格式

文本(UTF-8 编码)

任意数据格式

使用场景

数据流推送、实时通知

实时交互、大量数据传输


7. 优势与局限

优势:
  1. 轻量化:简单易用,基于 HTTP。

  2. 自动重连:无需手动管理断线重连。

  3. 浏览器支持好:大多数现代浏览器原生支持。

  4. 节省资源:只需要单向通信时,比 WebSocket 更省资源。

局限:
  1. 单向通信:只能服务器向客户端推送数据。

  2. 功能有限:不支持二进制数据传输,只能发送文本数据。

  3. 跨域限制:SSE 需要处理跨域问题。