穿着球衣 2 直播?

dev*_*rts 4 java json jetty dropwizard jersey-2.0

我一直在尝试让 json 流在 jersey 2 中工作。在我的一生中,在流完成之前没有任何流。

我尝试过这个示例,试图模拟缓慢的数据生成器。

@Path("/foo")
@GET
public void getAsyncStream(@Suspended AsyncResponse response) {
    StreamingOutput streamingOutput = output -> {

        JsonGenerator jg = new ObjectMapper().getFactory().createGenerator(output, JsonEncoding.UTF8);
        jg.writeStartArray();

        for (int i = 0; i < 100; i++) {
            jg.writeObject(i);

            try {
                Thread.sleep(100);
            }
            catch (InterruptedException e) {
                logger.error(e, "Error");
            }
        }

        jg.writeEndArray();

        jg.flush();
        jg.close();

    };

    response.resume(Response.ok(streamingOutput).build());
}
Run Code Online (Sandbox Code Playgroud)

然而 jersey 只是坐在那里,直到 json 生成器完成返回结果为止。我正在观察查尔斯代理中的结果。

我需要启用某些功能吗?不知道为什么这不会流出


编辑:

这实际上可能有效,只是不是我预期的那样。我不认为流正在实时写入内容,这正是我想要的,它更多的是不必缓冲响应并立即将它们写出给客户端。如果我运行一百万个循环并且没有线程睡眠,那么数据确实会以块的形式写出,而无需将其缓冲在内存中。

Pau*_*tha 5

您的编辑正确。它正在按预期工作。StreamingOutput只是一个包装器,让我们直接写入响应流,但实际上并不意味着响应在每个服务器端流式传输到写入流。AsyncResponse就客户而言,也不提供任何不同的响应。它只是为了帮助提高长时间运行任务的吞吐量。长时间运行的任务实际上应该在另一个线程中完成,以便该方法可以返回。

您似乎正在寻找的是分块输出

Jersey 提供了一种工具,可以使用分块输出以多个或多或少独立的块的形式向客户端发送响应。每个响应块在发送到客户端之前通常需要一些(更长)的时间来准备。关于响应块的最重要的事实是,您希望在它们可用时立即将它们发送到客户端,而不是等待剩余的块也变得可用。

不确定它如何适用于您的特定用例,正如JsonGenerator预期的那样OutputStream(我们ChuckedOutput使用的不是),但这是一个更简单的示例

@Path("async")
public class AsyncResource {

    @GET
    public ChunkedOutput<String> getChunkedStream() throws Exception {
        final ChunkedOutput<String> output = new ChunkedOutput<>(String.class);

        new Thread(() -> {
            try {
                String chunk = "Message";

                for (int i = 0; i < 10; i++) {
                    output.write(chunk + "#" + i);
                    Thread.sleep(1000);
                }
            } catch (Exception e) {
            } finally {
                try {
                    output.close();
                } catch (IOException ex) {
                    Logger.getLogger(AsyncResource.class.getName())
                          .log(Level.SEVERE, null, ex);
                }
            }
        }).start();
        return output;
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:一开始我在让它工作时遇到了问题。我只会得到延迟的完整结果。问题似乎出在与程序完全无关的东西上。实际上是我的 AVG 造成了这个问题。一些称为“LinkScanner”的功能正在阻止此分块过程的发生。我禁用了该功能,它开始工作。

我还没有对分块进行太多探索,并且不确定安全隐患,所以我不确定为什么 AVG 应用程序会出现问题。

在此输入图像描述


编辑

似乎真正的问题是由于 Jersey 缓冲响应以计算 Content-Length 标头。您可以参阅这篇文章了解如何更改此行为