Java jersey - StreamingOutput 作为响应实体
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29637151/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
jersey - StreamingOutput as Response entity
提问by PrabhaT
I had implemented streaming output in my Jersey Resource class.
我在 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
}
}
The problem is eventhough a response is sent back from the resource before FeedReturnStreamingOutput is called Jersey client waits until FeedReturnStreamingOutput execution is completed.
问题是即使在调用 FeedReturnStreamingOutput 之前从资源发回响应 Jersey 客户端等待 FeedReturnStreamingOutput 执行完成。
Client Code :
客户代码:
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");
采纳答案by Paul Samsotha
The problem is the buffering OutputStream
that Jersey uses to buffer the entity in order to determine the Content-Length header. The size of the buffer default to 8 kb. You disable the buffering if you want, or just change the size of the buffer, with the property
问题OutputStream
在于 Jersey 用于缓冲实体以确定 Content-Length 标头的缓冲。缓冲区的大小默认为 8 kb。如果需要,您可以禁用缓冲,或者只是使用属性更改缓冲区的大小
ServerProperties.OUTBOUND_CONTENT_LENGTH_BUFFER
An integer value that defines the buffer size used to buffer server-side response entity in order to determine its size and set the value of HTTP "Content-Length" header.
If the entity size exceeds the configured buffer size, the buffering would be cancelled and the entity size would not be determined. Value less or equal to zero disable the buffering of the entity at all.
This property can be used on the server side to override the outbound message buffer size value - default or the global custom value set using the "jersey.config.contentLength.buffer" global property.
The default value is 8192.
ServerProperties.OUTBOUND_CONTENT_LENGTH_BUFFER
一个整数值,定义用于缓冲服务器端响应实体的缓冲区大小,以确定其大小并设置 HTTP“Content-Length”标头的值。
如果实体大小超过配置的缓冲区大小,则缓冲将被取消,实体大小将无法确定。值小于或等于零将完全禁用实体的缓冲。
此属性可用于服务器端覆盖出站消息缓冲区大小值 - 默认或使用“jersey.config.contentLength.buffer”全局属性设置的全局自定义值。
默认值为 8192。
Here's an example
这是一个例子
@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); }
}
}
}
Here's the result without setting the property
这是没有设置属性的结果
And here's the result after setting the property value to 0
这是将属性值设置为后的结果 0
public class AppConfig extends ResourceConfig {
public AppConfig() {
...
property(ServerProperties.OUTBOUND_CONTENT_LENGTH_BUFFER, 0);
}
}
回答by Montecarlo
Try invoking outputStream.flush()
from the method FeedReturnStreamingOutput.write(...)
every X number of bytes written to the output stream or something like that.
尝试outputStream.flush()
从FeedReturnStreamingOutput.write(...)
写入输出流的每 X 个字节或类似的方法调用该方法。
I guess the buffer of the connection is not filled with the data you are returning. So the service does not return anything until Jersey invokes outputStream.close()
.
我猜连接的缓冲区没有填充您返回的数据。因此,该服务在 Jersey 调用之前不会返回任何内容outputStream.close()
。
In my case, I have a service that streams data and I am doing it exactly as you: by returning Response.ok(<instance of StreamingOutput>).build();
.
就我而言,我有一个流式传输数据的服务,并且我正在按照您的方式进行操作:通过返回Response.ok(<instance of StreamingOutput>).build();
.
My service returns data from a database and I invoke outputStream.flush()
after writing each row to the output stream.
我的服务从数据库返回数据,并outputStream.flush()
在将每一行写入输出流后调用。
I know that the service streams data because I can see the client begins receiving data before the service has finished sending the entire result.
我知道服务流数据,因为我可以看到客户端在服务完成发送整个结果之前开始接收数据。
回答by Daniel Sperry
Either your response is too small and never gets chunkedso the server flushes the entire request at once. Or you have a server side issue were your jax-rs library is awaiting to have the complete stream before flushing.
要么你的响应太小,永远不会被分块,所以服务器一次刷新整个请求。或者你有一个服务器端问题,你的 jax-rs 库在刷新之前等待拥有完整的流。
However this looks more like a client problem. And you seem to be using an old version of jersey-client.
但是,这看起来更像是客户端问题。而且您似乎使用的是旧版本的 jersey-client。
Also that .get(ClientResponse.class)
looks fishy.
还有那.get(ClientResponse.class)
看起来很腥。
Try using the JAX-RS standard as it is today (at least in the client):
尝试使用现在的 JAX-RS 标准(至少在客户端中):
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target("http://localhost:8080/");
Response response = target.path("path/to/resource").request().get();
While having jersey client 2.17 in the classpath:
在类路径中有 jersey 客户端 2.17 时:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.17</version>
</dependency>
回答by Mike Dias
I just realized that if you use a subclass of StreamingOutput, Jersey don't stream the response:
我刚刚意识到,如果您使用 StreamingOutput 的子类,Jersey 不会流式传输响应:
// works fine
Response.ok(new StreamingOutput() { ... }).build();
// don't work
public interface MyStreamingOutput extends StreamingOutput { }
Response.ok(new MyStreamingOutput() { ... }).build();
Is that a Jersey bug?
这是泽西岛的虫子吗?