tio-boot 整合 Server-Sent Events (SSE)

SSE 简介

Server-Sent Events(SSE)是一种允许服务器主动向客户端发送信息的技术。与 WebSocket 不同,SSE 是单向通信,仅服务器能向客户端发送数据。这使得 SSE 非常适合于需要服务器实时推送数据但客户端不需要发送信息的场景,例如实时通知和更新。

tio-boot 中整合 SSE 的步骤

整合 SSE 到 tio-boot 框架中可以让你的应用具备实时数据推送的能力。以下是在 tio-boot 框架中创建一个简单的 SSE 应用的步骤和代码示例:

步骤 1: 创建 SSE Controller

首先,创建一个名为 SseController 的类,并用 @RequestPath 注解标记该类和方法。该方法将处理来自 /sse 路径的 SSE 请求。

package com.litongjava.ai.chat.controller;

import com.litongjava.tio.core.Tio;
import com.litongjava.tio.http.common.HttpRequest;
import com.litongjava.tio.http.common.HttpResponse;
import com.litongjava.tio.http.server.annotation.RequestPath;
import com.litongjava.tio.http.server.sse.SsePacket;
import com.litongjava.tio.server.ServerChannelContext;

import lombok.extern.slf4j.Slf4j;

@RequestPath("/sse")
@Slf4j
public class SseController {

  @RequestPath
  public HttpResponse conversation(HttpRequest request, ServerChannelContext channelContext) {
    // ... (代码继续)
  }
}
步骤 2: 设置 SSE 请求头并发送响应

conversation 方法中,首先设置 SSE 请求头,并发送一个空的响应来初始化 SSE 连接。

// 设置 SSE 请求头
HttpResponse httpResponse = new HttpResponse(request).setServerSentEventsHeader();
Tio.send(channelContext, httpResponse);
log.info("已经响应请求头");
步骤 3: 发送 SSE 消息

使用 SsePacket 来构造并发送 SSE 消息。在这个例子中,我们通过一个循环发送了 10 条消息。

new Thread(() -> {
  for (int i = 0; i < 10; i++) {
    // ... (循环内容)
  }
  // 手动移除连接
  Tio.remove(channelContext, "remove sse");
}).start();
步骤 4: 测试 SSE 功能

要测试你的 SSE 服务,你可以使用 curl 命令访问 SSE 路径:

curl http://localhost/sse

测试结果应该显示一系列格式化的 SSE 消息:

id:1
event:message
data:This is message 0

id:2
event:message
data:This is message 1

...

每条消息都包含一个唯一的 id,事件类型 event,以及实际的消息内容 data

完整的 Cotnroller

package com.litongjava.ai.chat.controller;

import com.litongjava.tio.core.Tio;
import com.litongjava.tio.http.common.HttpRequest;
import com.litongjava.tio.http.common.HttpResponse;
import com.litongjava.tio.http.server.annotation.RequestPath;
import com.litongjava.tio.http.server.sse.SsePacket;
import com.litongjava.tio.server.ServerChannelContext;

import lombok.extern.slf4j.Slf4j;

@RequestPath("/sse")
@Slf4j
public class SseController {

  @RequestPath
  public HttpResponse conversation(HttpRequest request, ServerChannelContext channelContext) {
    // 设置sse请求头
    HttpResponse httpResponse = new HttpResponse(request).setServerSentEventsHeader();
    // 手动发送消息到客户端,因为已经设置了sse的请求头,所以客户端的连接不会关闭
    Tio.send(channelContext, httpResponse);
    log.info("已经相应请求头");
    new Thread(() -> {
      for (int i = 0; i < 10; i++) {
        String id = i + "";
        String eventName = "message";
        String data = "This is message " + i;
        SsePacket ssePacket = new SsePacket().eventId(id).name(eventName).data(data);
        // 再次向客户端发送消息
        Tio.send(channelContext, ssePacket);
        log.info("发送数据:{}", i);
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      //手动移除连接
      Tio.remove(channelContext, "remove sse");
    }).start();

    // 告诉处理器不要将消息发送给客户端
    return new HttpResponse().setSend(false);

  }
}

总结

通过上述步骤,你可以在 tio-boot 框架中成功整合 SSE,从而使你的应用能够实时地向客户端推送数据。这种方法的优点在于其简单性和低延迟,非常适用于需要服务器实时更新的场景。


李通
215 声望0 粉丝