【问题标题】:Streaming in jersey 2?在球衣 2 中流媒体?
【发布时间】:2015-06-29 08:56:08
【问题描述】:

我一直在尝试让 json 流在球衣 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());
}

然而 jersey 只是坐在那里,直到 json 生成器完成返回结果。我正在看结果是通过 charles 代理获得的。

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


编辑:

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

【问题讨论】:

  • 你是怎么解决这个问题的?
  • @gkiko 接受的答案解决了我的问题。流媒体不是分块。这就是我的困惑。
  • 查看我的编辑。如果这是你正在做的事情。将链接中提到的属性设置为小尺寸或 0,将允许流以您期望的方式工作。

标签: java json jetty jersey-2.0 dropwizard


【解决方案1】:

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

您似乎正在寻找的是Chunked Output

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;
    }
}

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

我没有深入研究分块,也不确定安全隐患,所以我不确定为什么 AVG 应用程序会出现问题。


编辑

似乎真正的问题是由于 Jersey 缓冲响应以计算 Content-Length 标头。您可以查看 this post 了解如何更改此行为

【讨论】:

    猜你喜欢
    • 2014-05-04
    • 1970-01-01
    • 2016-01-03
    • 1970-01-01
    • 2014-06-28
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    • 2015-02-08
    相关资源
    最近更新 更多