如何使用 JAX-RS 连续流式传输文本数据

How to stream text data with JAX-RS continuously

我阅读了多个与我相似的问题并发现了这个:

但是我做不到。我使用纯 JAX-RS API 和 Open Liberty 作为我的服务器。不幸的是找不到 ResourceConfig,所以我无法禁用缓冲区,如上面的答案所述。

这是我的代码:

@GET
@Produces(MediaType.TEXT_PLAIN)
public Response sayHelloStream() {
    LOGGER.debug("calling sayHelloStream");
    StreamingOutput out = outputStream -> {
        Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        for (int i = 0; i < 999999999; i++) {
            writer.write("Hello\n");
            writer.flush();

            try {
                LOGGER.debug("before sleep");
                TimeUnit.SECONDS.sleep(3);
                LOGGER.debug("after sleep");
            } catch (InterruptedException e) {
                LOGGER.error("error with the timer", e);
            }
        }
    };
    return Response.ok(out).build();
}

在浏览器中调用它时没有任何反应。据我了解,由于缓冲区。我如何使用纯 JAX-RS 像这样流式传输文本数据?

我会使用 SSE 扩展。据我所知,它是 JAX-RS API 的一部分,尽管您可能需要一个额外的模块来启用它 server-side:

https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/sse.html

...
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseEventSink;
import javax.ws.rs.sse.OutboundSseEvent;
...
 
@Path("events")
public static class SseResource {
 
    @GET
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public void getServerSentEvents(@Context SseEventSink eventSink, @Context Sse sse) {
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                // ... code that waits 1 second
                final OutboundSseEvent event = sse.newEventBuilder()
                    .name("message-to-client")
                    .data(String.class, "Hello world " + i + "!")
                    .build();
                eventSink.send(event);
            }
        }).start();
    }
}

它以 SSE 格式的块将文本数据流式传输到客户端,因此可以在浏览器中轻松处理,例如使用HTML5 <eventsource> 元素或 EventSource JavaScript API.

var source = new EventSource('.../events');
source.addEventListener('message-to-client', function(e) {
  console.log(e.data);
}, false);