2015-04-14 58 views
13

我已經在我的Jersey資源類中實現了流輸出。球衣 - StreamingOutput作爲響應實體

@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 
    } 
} 

的問題是eventhough發送響應從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"); 

回答

21

問題是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); } 
     } 
    } 
} 

這裏的結果,而不設置屬性

enter image description here

這裏設置該屬性後的結果價值到0

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

enter image description here

+0

這是一個很好的解決方案。我剛剛發現的一件事 - 只有在輸入結尾處有換行符的情況下才有效:) – pandaadb

1

嘗試從方法FeedReturnStreamingOutput.write(...)寫入到輸出流或類似的東西字節的每X數量調用outputStream.flush()

我想連接的緩衝區沒有填充您返回的數據。因此,在澤西調用outputStream.close()之前,該服務不會返回任何內容。

在我的情況下,我有一個服務,流數據,我完全按照您的方式:通過返回Response.ok(<instance of StreamingOutput>).build();

我的服務從數據庫返回數據,並且在將每行寫入輸出流後調用outputStream.flush()

我知道服務流數據,因爲我可以看到客戶端在服務完成發送整個結果之前開始接收數據。

+0

我加入outputstream.flush每次我寫到輸出流中。沒有任何區別 – PrabhaT

+0

@ user1016496你怎麼知道服務不是流式的? 難道這服務實際上是流式傳輸數據,但客戶端不是在流式傳輸模式下編寫它獲得的內容嗎? – Montecarlo

1

您的響應太小,從來沒有得到chunked,所以服務器一次沖刷整個請求。或者你有一個服務器端問題,你的jax-rs庫正在等待沖洗之前完整的流。

但是,這看起來更像是一個客戶端問題。而且你似乎正在使用舊版的球衣客戶端。

此外.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(); 

雖然有在classpath球衣客戶2.17:

<dependency> 
    <groupId>org.glassfish.jersey.core</groupId> 
    <artifactId>jersey-client</artifactId> 
    <version>2.17</version> 
</dependency> 
0

我剛剛意識到,如果你使用StreamingOutput的子類,澤西島不流式響應:

// works fine 
Response.ok(new StreamingOutput() { ... }).build(); 

// don't work 
public interface MyStreamingOutput extends StreamingOutput { } 
Response.ok(new MyStreamingOutput() { ... }).build(); 

是那麼一個澤西蟲?

+0

「意料之中」是什麼意思? –

+0

我的意思是傳遞迴應。我會更新答案。 –

+0

我不認爲這是問題。所有[作者](https://github.com/jersey/jersey/blob/master/core-common/src/main/java/org/glassfish/jersey/message/internal/StreamingOutputProvider.java#L75)都是調用傳遞給實體OutputStream的'write'方法。沒有別的特別的事情發生。流媒體問題與Jersey用來計算內容長度的緩衝輸出流有關。您可以通過[this property](https://jersey.java.net/apidocs/2.22/jersey/org/glassfish/jersey/server/ServerProperties.html#OUTBOUND_CONTENT_LENGTH_BUFFER)將其禁用設置爲0. –