java - 如何更改 Jersey EventInput 使用的分隔符

标签 java jersey server-sent-events eventsource

我需要订阅 SSE(服务器发送事件)。我知道标准规定事件之间的分隔符应该是“\r\n\r\n” - 检查此处语法中的“行尾”:

https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream

但是我应该使用的流不遵循标准并用“\n”分隔。

我决定对 Jersey EventInput 类进行替代实现,您可以在此处看到:

https://github.com/jersey/jersey/blob/12e5d8bdf22bcd2676a1032ed69473cf2bbc48c7/media/sse/src/main/java/org/glassfish/jersey/media/sse/EventInput.java

因此,我的实现将复制 EventInput,唯一的区别是指定的分隔符。它看起来像:

public class MyEventInput extends ChunkedInput<InboundEvent> {
/**
 * SSE event chunk parser - SSE chunks are delimited with a fixed "\n" and "\r\n\r\n" delimiter in the response stream.
 */
private static final ChunkParser SSE_EVENT_PARSER = ChunkedInput.createMultiParser("\n", "\r\n\r\n");

编译器完全接受我的实现,但是当我尝试运行它时,它不起作用!它卡在以下行中:

final MyEventInput eventInput = target.register(SseFeature.class)
                                .request().get(MyEventInput.class);

如果我执行以下操作,它就可以正常工作:

final EventInput eventInput = target.register(SseFeature.class)
                                .request().get(EventInput.class);

我开始调试,发现 Jersey 使用一个名为 MessageBodyFactory 的类,它会进行如下检查:

if (isCompatible(model, c, mediaType)) 

if (model.isReadable(c, t, as, mediaType))

https://github.com/jersey/jersey/blob/12e5d8bdf22bcd2676a1032ed69473cf2bbc48c7/core-common/src/main/java/org/glassfish/jersey/message/internal/MessageBodyFactory.java#L685

他们检查你的类(class)是否是有效的读者。有效的读者是通过以下方式获得的(至少在我看来,在调试时......):

final Set<MessageBodyReader> customMbrs = Providers.getCustomProviders(injectionManager, MessageBodyReader.class);
final Set<MessageBodyReader> mbrs = Providers.getProviders(injectionManager, MessageBodyReader.class);

所以我的问题是...如何将 MyEventInput 注册为有效的读取器,以便我可以使用它来订阅以自定义分隔符分隔的 SSE 流?

最佳答案

好吧,由于我没有找到其他解决方案,我只是用反射“破解”了 Jersey 库,并为 EventInput 类指定了不同的解析器。这是我的做法(在实例化 EventInput 之前,您必须重新定义 SSE_EVENT_PARSER 字段...):

Field f = EventInput.class.getDeclaredField("SSE_EVENT_PARSER");
f.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);

f.set(null, ChunkedInput.createMultiParser("\n", "\r\n\r\n"));

final EventInput eventInput = target.request().get(EventInput.class);

关于java - 如何更改 Jersey EventInput 使用的分隔符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49878543/

相关文章:

java - 响应中的 JAX/Jersey 自定义错误代码

java - uriBuilder 返回 http :/instead of http://

javascript - 如何使 EventSource 在 FireFox 的 SharedWorker 中可用?

java - 如何重写 Spring Boot RequestMappingHandlerMapping?

java - @RespositoryRestController 中的空身份验证@WithUserDetails

java - 将授权 header 添加到 Jersey SSE 客户端请求

java - 服务器发送的事件在 Google Chrome 中不起作用

java - 重用 StringBuilder 和 ArrayIndexOutOfBoundsException

java - 索引 0 超出范围

json - 服务器可以通过 POST 发送带有 EventSource 传递参数的事件 (SSE)