0

我需要订阅 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

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

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

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

4

1 回答 1

1

好的,因为我没有找到其他解决方案,所以我只是用反射“破解”了 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);
于 2018-04-18T11:52:48.440 回答