我在Jersey Resource类中实现了流输出。
@GET
@Path("xxxxx")
@Produces(BulkConstants.TEXT_XML_MEDIA_TYPE})
public Response getFile() {
FeedReturnStreamingOutput sout = new FeedReturnStreamingOutput();
response = Response.ok(sout).build();
return response;
}
class FeedReturnStreamingOutput implements StreamingOutput {
public FeedReturnStreamingOutput()
@Override
public void write(OutputStream outputStream) {
//write into Output Stream
}
}
问题是尽管在调用FeedReturnStreamingOutput之前从资源发回响应但是Jersey客户端等待直到FeedReturnStreamingOutput执行完毕。
客户代码:
Client client = Client.create();
ClientResponse response = webResource
//headers
.get(ClientResponse.class);
//The codes underneath executes after FeedReturnStreamingOutput is executed which undermines the necessity of streaming
OutputStream os = new FileOutputStream("c:\\test\\feedoutput5.txt");
System.out.println(new Date() + " : Reached point A");
if (response.getStatus() == 200) {
System.out.println(new Date() + " : Reached point B");
InputStream io = response.getEntityInputStream();
byte[] buff = new byte[1024000];
int count = 0;
while ((count = io.read(buff, 0, buff.length)) != -1) {
os.write(buff, 0, count);
}
os.close();
io.close();
} else {
System.out.println("Response code :" + response.getStatus());
}
System.out.println("Time taken -->> "+(System.currentTimeMillis()-startTime)+" ms");
答案 0 :(得分:33)
问题是Jersey用来缓冲实体以确定Content-Length头的缓冲OutputStream
。缓冲区的大小默认为8 kb。如果需要,可以使用属性
ServerProperties.OUTBOUND_CONTENT_LENGTH_BUFFER
一个整数值,它定义用于缓冲服务器端响应实体的缓冲区大小,以确定其大小并设置HTTP“Content-Length”标头的值。
如果实体大小超过配置的缓冲区大小,则将取消缓冲并且不确定实体大小。值小于或等于零会禁用实体的缓冲。
可以在服务器端使用此属性来覆盖出站消息缓冲区大小值 - 默认值或使用“jersey.config.contentLength.buffer”全局属性设置的全局自定义值。
默认值为8192。
这是一个例子
@Path("streaming")
public class StreamingResource {
@GET
@Produces("application/octet-stream")
public Response getStream() {
return Response.ok(new FeedReturnStreamingOutput()).build();
}
public static class FeedReturnStreamingOutput implements StreamingOutput {
@Override
public void write(OutputStream output)
throws IOException, WebApplicationException {
try {
for (int i = 0; i < 10; i++) {
output.write(String.format("Hello %d\n", i).getBytes());
output.flush();
TimeUnit.MILLISECONDS.sleep(500);
}
} catch (InterruptedException e) { throw new RuntimeException(e); }
}
}
}
这是没有设置属性的结果
这是将属性值设置为0
public class AppConfig extends ResourceConfig {
public AppConfig() {
...
property(ServerProperties.OUTBOUND_CONTENT_LENGTH_BUFFER, 0);
}
}
答案 1 :(得分:1)
尝试从方法outputStream.flush()
中调用FeedReturnStreamingOutput.write(...)
每X个字节写入输出流或类似的东西。
我猜连接的缓冲区没有填充您要返回的数据。因此,在Jersey调用outputStream.close()
之前,服务不会返回任何内容。
在我的情况下,我有一个流式传输数据的服务,我的工作方式与您完全一样:返回Response.ok(<instance of StreamingOutput>).build();
。
我的服务从数据库返回数据,并在将每一行写入输出流后调用outputStream.flush()
。
我知道服务流数据,因为我可以看到客户端在服务发送完整个结果之前就开始接收数据。
答案 2 :(得分:0)
我刚刚意识到如果你使用StreamingOutput的子类,Jersey不会传输响应:
// works fine
Response.ok(new StreamingOutput() { ... }).build();
// don't work
public interface MyStreamingOutput extends StreamingOutput { }
Response.ok(new MyStreamingOutput() { ... }).build();
这是泽西岛的错误吗?