球衣 - StreamingOutput 作为响应实体
jersey - StreamingOutput as Response entity
我在我的 Jersey 资源中实现了流式输出 class。
@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");
尝试从方法 FeedReturnStreamingOutput.write(...)
调用 outputStream.flush()
每 X 个字节写入输出流或类似的东西。
我猜连接的缓冲区中没有填充您正在 returning 的数据。因此,在 Jersey 调用 outputStream.close()
.
之前,该服务不会 return 任何东西
就我而言,我有一项流式传输数据的服务,我正在按照您的方式进行操作:通过 returning Response.ok(<instance of StreamingOutput>).build();
.
我的服务 returns 来自数据库的数据,我在将每一行写入输出流后调用 outputStream.flush()
。
我知道服务流式传输数据,因为我可以看到客户端在服务完成发送整个结果之前就开始接收数据。
要么您的响应太小,永远不会得到 chunked,因此服务器会立即刷新整个请求。或者你有一个服务器端问题,你的 jax-rs 库在刷新之前等待拥有完整的流。
然而,这看起来更像是客户端问题。而且您似乎使用的是旧版本的 jersey-client。
另外 .get(ClientResponse.class)
看起来很可疑。
尝试使用当今的 JAX-RS 标准 (at least in the client):
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();
类路径中有 jersey client 2.17 时:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.17</version>
</dependency>
问题是 Jersey 用来缓冲实体以确定 Content-Length header 的缓冲 OutputStream
。缓冲区的大小默认为 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.
这是一个例子
@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);
}
}
我在我的 Jersey 资源中实现了流式输出 class。
@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");
尝试从方法 FeedReturnStreamingOutput.write(...)
调用 outputStream.flush()
每 X 个字节写入输出流或类似的东西。
我猜连接的缓冲区中没有填充您正在 returning 的数据。因此,在 Jersey 调用 outputStream.close()
.
就我而言,我有一项流式传输数据的服务,我正在按照您的方式进行操作:通过 returning Response.ok(<instance of StreamingOutput>).build();
.
我的服务 returns 来自数据库的数据,我在将每一行写入输出流后调用 outputStream.flush()
。
我知道服务流式传输数据,因为我可以看到客户端在服务完成发送整个结果之前就开始接收数据。
要么您的响应太小,永远不会得到 chunked,因此服务器会立即刷新整个请求。或者你有一个服务器端问题,你的 jax-rs 库在刷新之前等待拥有完整的流。
然而,这看起来更像是客户端问题。而且您似乎使用的是旧版本的 jersey-client。
另外 .get(ClientResponse.class)
看起来很可疑。
尝试使用当今的 JAX-RS 标准 (at least in the client):
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();
类路径中有 jersey client 2.17 时:
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.17</version>
</dependency>
问题是 Jersey 用来缓冲实体以确定 Content-Length header 的缓冲 OutputStream
。缓冲区的大小默认为 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.
这是一个例子
@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);
}
}