OkHttp SSE 模块详解

730 阅读5分钟

OkHttp SSE 模块详解

什么是 Server-Sent Events (SSE)

Server-Sent Events (SSE) 是一种基于 HTTP 的服务器推送技术,允许服务器通过单个 HTTP 连接向客户端发送事件流。SSE 建立了一个长连接,服务器可以通过这个连接持续地向客户端推送数据,而无需客户端重复发起请求。

核心特点

  • 单向通信:服务器向客户端推送数据,客户端不能通过同一连接向服务器发送数据

  • 基于 HTTP:使用标准 HTTP 协议,Content-Type 为 text/event-stream

  • 自动重连:客户端在连接断开后会自动尝试重新连接

  • 事件 ID:支持事件 ID,可以在重连后恢复之前的状态

  • 基于纯文本:使用简单的文本格式传输数据

SSE 数据格式示例

event: userconnect
data: {"username": "bobby", "time": "02:33:48"}
id: 1

event: usermessage
data: {"username": "bobby", "message": "Hi everyone!"}
id: 2

SSE vs WebSocket

特性SSEWebSocket
通信方向单向(服务器到客户端)双向
协议HTTPWebSocket(初始握手基于HTTP)
复杂度简单相对复杂
自动重连原生支持需要自行实现
数据格式文本文本或二进制
跨域限制受同源策略限制较少限制
适用场景实时通知、新闻推送、股票行情聊天应用、多人游戏、协作工具

OkHttp SSE 模块的功能和用途

OkHttp SSE 模块是 OkHttp 库的扩展,提供了在 Android 和 Java 应用中使用 SSE 的能力。它封装了 SSE 的连接建立、事件解析和错误处理等复杂逻辑,让开发者可以简单地实现服务器推送功能。

主要功能

1. 建立 SSE 连接:通过 HTTP 请求建立与 SSE 服务器的连接

2. 事件解析:解析服务器发送的事件流,提取事件类型、数据和ID

3. 自动重连:在连接断开时自动重新连接

4. 事件监听:通过 EventSourceListener 接收和处理事件

5. 连接管理:提供取消连接的方法

使用场景

SSE 技术和 OkHttp SSE 模块适用于以下场景:

1. 实时通知系统:如新邮件提醒、系统通知等

2. 实时数据更新:股票价格、体育比分、天气更新等

3. 社交媒体动态:新的评论、点赞、关注等通知

4. 日志流:实时查看服务器日志

5. 进度更新:长时间运行任务的进度报告

优势

1. 简单易用:相比 WebSocket,SSE 实现更简单,API 更直观

2. HTTP 兼容:使用标准 HTTP,可以利用现有的 HTTP 基础设施(代理、缓存等)

3. 轻量级:协议简单,资源消耗较小

4. 自动重连:内置重连机制,提高了连接的可靠性

5. 与 OkHttp 集成:可以复用 OkHttp 的连接池、拦截器等功能

代码示例

以下是使用 OkHttp SSE 模块的完整示例:

import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.sse.EventSource
import okhttp3.sse.EventSourceListener
import okhttp3.sse.EventSources
import java.util.concurrent.TimeUnit

fun main() {
    // 1. 创建 OkHttpClient
    val client = OkHttpClient.Builder()
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(90, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .build()
    
    // 2. 创建 EventSource.Factory
    val factory = EventSources.createFactory(client)
    
    // 3. 创建 Request
    val request = Request.Builder()
        .url("https://example.com/sse-endpoint")
        .header("Accept", "text/event-stream")
        .build()
    
    // 4. 创建 EventSourceListener
    val listener = object : EventSourceListener() {
        override fun onOpen(eventSource: EventSource, response: Response) {
            println("SSE connection opened: ${response.code}")
        }
        
        override fun onEvent(
            eventSource: EventSource,
            id: String?,
            type: String?,
            data: String
        ) {
            println("Event received:")
            println("  id: $id")
            println("  type: $type")
            println("  data: $data")
            
            // 处理不同类型的事件
            when (type) {
                "update" -> handleUpdate(data)
                "notification" -> showNotification(data)
                null -> handleDefaultEvent(data)
            }
        }
        
        override fun onClosed(eventSource: EventSource) {
            println("SSE connection closed normally")
        }
        
        override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
            println("SSE connection failed: ${t?.message}")
            response?.let { println("Response code: ${it.code}") }
            
            // 可以在这里实现自定义的重连逻辑
        }
    }
    
    // 5. 创建并启动 EventSource
    val eventSource = factory.newEventSource(request, listener)
    
    // 应用运行...
    
    // 6. 在适当的时候取消连接
    // eventSource.cancel()
}

// 事件处理函数
fun handleUpdate(data: String) {
    println("Processing update: $data")
}

fun showNotification(data: String) {
    println("Showing notification: $data")
}

fun handleDefaultEvent(data: String) {
    println("Processing default event: $data")
}

OkHttp SSE 实现原理

OkHttp 的 SSE 模块通过以下组件和流程实现 SSE:

核心组件

1. EventSource 接口:定义 SSE 连接的基本操作

2. EventSourceListener:处理连接状态和接收事件的回调

3. RealEventSource:EventSource 的实际实现

4. ServerSentEventReader:解析 SSE 事件流

实现流程

1. 连接建立

  • RealEventSource 使用 OkHttp 的 Call 接口发起 HTTP 请求

  • 验证响应的 Content-Type 是否为 text/event-stream

  • 建立长连接并获取响应体的 Source

2. 事件解析

  • ServerSentEventReader 从 Source 读取数据

  • 按照 SSE 规范解析事件行(event、data、id、retry)

  • 当收集到完整事件时,通过 EventSourceListener.onEvent() 回调通知客户端

3. 自动重连

  • 当连接断开时,根据服务器指定的 retry 值或默认值进行重连

  • 重连时携带上次接收到的最后一个事件 ID,服务器可以据此发送错过的事件

4. 错误处理

  • 网络错误、解析错误等通过 EventSourceListener.onFailure() 通知客户端

  • 客户端可以在此实现自定义的错误处理和重连策略

5. 资源释放

  • 当调用 EventSource.cancel() 或发生不可恢复的错误时

  • 关闭网络连接,释放相关资源

  • 通过 EventSourceListener.onClosed() 或 onFailure() 通知客户端

关键实现细节

  • 线程处理:事件解析和回调在 OkHttp 的后台线程池中进行,避免阻塞主线程

  • 缓冲管理:使用 Okio 库高效处理 I/O 操作和缓冲区管理

  • 连接复用:利用 OkHttp 的连接池机制,可能复用底层 TCP 连接

  • 拦截器兼容:完全兼容 OkHttp 的拦截器链,支持日志、认证等功能

通过这种实现,OkHttp SSE 模块提供了一个高效、可靠且易于使用的 SSE 客户端,同时充分利用了 OkHttp 的网络处理能力和扩展性。