来自Jersey REST服务的ChunkedOutput响应

时间:2016-11-04 18:05:49

标签: jersey streaming response

我正在tomcat上编写Jersey REST服务。 REST服务与数据库通信并将数据发送回REST客户端。我想将数据流回客户端,因此我的tomcat服务器不会因为数据库的巨大响应而崩溃,因为我不知道数据库响应大小是多少。我选择了从球衣的chunkedoutput。 (请注意,我已经使用测试方法模仿实际方法)下面是服务器端代码剪切,

@GET
@Path("numbers")
@Produces(MediaType.APPLICATION_JSON)
public ChunkedOutput<TestMessage> sendChunkedOutput() {
    final ChunkedOutput<TestMessage> output = new ChunkedOutput<TestMessage>(TestMessage.class,",");

    new Thread() {
        @Override
        public void run() {
            try {
                System.out.println("*** Writing the response in chunkedoutput");
                for (int i = 0; i < 100000; i++) {
                    output.write(getNumber(i));
                }
                System.out.println("*** completed wiriting output to chunkedoutpu1234");
                Thread.sleep(5000);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
    System.out.println("Thread is implemented and started ");
    return output;
}

public TestMessage getNumber(long l) {
    try {
        Thread.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return new TestMessage(l);
}

以下是客户端代码,

Client client = ClientBuilder.newClient();
client.property(ClientProperties.CHUNKED_ENCODING_SIZE, 100);
client.property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.CHUNKED);

Response response = client.target("http://localhost:8080/ChunkedServer/rest")
    .path("numbers").request()
    .property(ClientProperties.CHUNKED_ENCODING_SIZE, 100)
    .property(ClientProperties.REQUEST_ENTITY_PROCESSING, RequestEntityProcessing.CHUNKED)
    .get();

final ChunkedInput<String> input = response.readEntity(
    new GenericType<ChunkedInput<String>>() {}
);
String chunk;
while ((chunk = input.read()) != null) {
    System.out.println();
    if (chunk.length() == 0) {
        System.out.println("null");
    } else {
        System.out.println("chunk: " + chunk);
    }
}
}

不幸的是,即使我的服务器花费时间将数据发送回客户端,也不会以块的形式发送响应。完整响应仅在一次发送。 是什么原因导致分块输出没有发送给客户端?

1 个答案:

答案 0 :(得分:2)

正如Jersey documentation告诉我们的那样,ChunkedInput除了被告知之外不知道如何区分块,您需要在代码中添加自定义org.glassfish.jersey.client.ChunkParser或者确保服务器端使用默认的ChunkParser chunkDelimiter

文档(11.2.2。分块输入):

  

ChunkedInput不知道如何区分字节流中的块,除非被开发人员告知。

     

为了定义自定义块边界,ChunkedInput提供了注册ChunkParser的可能性,ChunkParser从输入流中读取块并将它们分开。

     

Jersey提供了几个块解析器实现,如果需要,您可以实现自己的解析器来分离块。

在不声明自己的解析器的情况下,Jersey使用默认解析器根据\r\n分隔字符序列的存在来分隔块

两种可能的选择:

1)使用自定义chunkDelimiter

由于您当前正在使用,作为服务器端chunkDelimiter,因此客户端应如下所示:

final ChunkedInput<String> input = response.readEntity(
    new GenericType<ChunkedInput<String>>() {}
);
input.setParser(ChunkedInput.createParser(","));
while ((chunk = input.read()) != null) {
    // [...]

2)使用默认的chunkDelimiter

服务器端:

final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class, "\r\n");

注意:
Jersey不使用ChunkParser构造函数中的默认chunkDelimiter ChunkedOutput。意思是......

final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class);

...将无效,因为默认值将设置为零长度分隔符(new byte[0])

度过美好的一天!