You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Jersey EventInput所使用的SSE事件分隔符?

解决非标准SSE分隔符的Jersey EventInput替代实现

遇到这种非标准SSE流的情况确实头疼,毕竟Jersey自带的EventInput是严格按照官方标准实现的。不过我们可以通过自定义一个替代类来解决这个问题,核心就是修改事件分隔符的解析逻辑。

核心实现思路

  • 我们需要自定义一个类似EventInput的类,重写其事件解析逻辑,将分隔符从标准的\r\n\r\n替换为\n
  • 要兼容SSE的字段规则:每个字段(比如event、data、id、retry)是以换行分隔的,非标准流里每个事件的结束就是单独的\n
  • 处理流读取时的缓冲逻辑,确保能正确分割每个完整的事件

关键代码示例

以下是自定义解析逻辑的核心部分(你可以基于Jersey原生EventInput的源码结构进行修改):

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class CustomEventInput implements Closeable {
    private final InputStream inputStream;
    private BufferedReader reader;
    // 替换为目标流使用的非标准分隔符
    private final String EVENT_DELIMITER = "\n";

    public CustomEventInput(InputStream inputStream) {
        this.inputStream = inputStream;
        this.reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
    }

    public InboundEvent read() throws IOException {
        StringBuilder eventContent = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            // 遇到分隔符,结束当前事件的读取
            if (line.isEmpty() && EVENT_DELIMITER.equals("\n")) {
                break;
            }
            eventContent.append(line).append("\n");
        }
        if (eventContent.length() == 0) {
            return null; // 流已读取完毕
        }
        // 解析事件的各个字段
        return parseEventFields(eventContent.toString());
    }

    private InboundEvent parseEventFields(String rawEvent) {
        InboundEvent event = new InboundEvent();
        String[] lines = rawEvent.split("\n");
        for (String line : lines) {
            if (line.startsWith("event:")) {
                event.setName(line.substring(6).trim());
            } else if (line.startsWith("data:")) {
                event.addData(line.substring(5).trim());
            } else if (line.startsWith("id:")) {
                event.setId(line.substring(3).trim());
            } else if (line.startsWith("retry:")) {
                try {
                    event.setRetry(Long.parseLong(line.substring(6).trim()));
                } catch (NumberFormatException e) {
                    // 处理无效的retry数值,可根据需求调整
                }
            }
            // 自动忽略以冒号开头的注释行
        }
        return event;
    }

    @Override
    public void close() throws IOException {
        reader.close();
        inputStream.close();
    }
}

注意事项

  • 测试边界场景:比如流末尾的不完整事件、连续的空分隔符、带有注释的事件行
  • 集成Jersey Client:在发起请求后,使用ClientResponse.readEntity(CustomEventInput.class)来获取自定义的事件输入流,替换原生的EventInput
  • 可扩展性:如果后续服务端修复为标准SSE格式,直接切换回原生EventInput即可,无需大量修改代码

内容的提问来源于stack exchange,提问作者pinpinokio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:17:51