球衣 - 流输出作为响应实体

2022-09-01 11:43:42

我已经在我的泽西岛资源类中实现了流式输出。

@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");

答案 1

问题在于泽西岛用于缓冲实体以确定内容长度标头的缓冲。缓冲区的大小默认为 8 kb。如果需要,可以禁用缓冲,或者只是使用属性更改缓冲区的大小OutputStream

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); }
        }
    }
}

下面是未设置属性的结果

enter image description here

这是将属性值设置为0

public class AppConfig extends ResourceConfig {
    public AppConfig() {
        ...
        property(ServerProperties.OUTBOUND_CONTENT_LENGTH_BUFFER, 0);
    }
}

enter image description here


答案 2

尝试从该方法调用写入输出流的每 X 个字节或类似的东西。outputStream.flush()FeedReturnStreamingOutput.write(...)

我猜连接的缓冲区没有填充您要返回的数据。因此,在 Jersey 调用 之前,该服务不会返回任何内容。outputStream.close()

在我的情况下,我有一个流式传输数据的服务,我完全按照您的方式进行:通过返回.Response.ok(<instance of StreamingOutput>).build();

我的服务从数据库返回数据,并在将每行写入输出流后调用。outputStream.flush()

我知道服务流式传输数据,因为我可以看到客户端在服务完成发送整个结果之前开始接收数据。


推荐