我正在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);
}
}
}
不幸的是,即使我的服务器花费时间将数据发送回客户端,也不会以块的形式发送响应。完整响应仅在一次发送。 是什么原因导致分块输出没有发送给客户端?
答案 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])
度过美好的一天!