2015-04-14 7 views
13

ich Streaming-Ausgabe in meiner Jersey Ressource Klasse implementiert hatte.Trikot - StreamingOutput als Antwort Einheit

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

Das Problem ist, obwohl eine Antwort von der Ressource zurückgesendet wird, bevor FeedReturnStreamingOutput heißt Jersey Client wartet, bis FeedReturnStreamingOutput Ausführung abgeschlossen ist.

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

Antwort

21

Das Problem ist die Pufferung OutputStream, die Jersey verwendet, um die Entität zu puffern, um den Content-Length-Header zu bestimmen. Die Größe des Puffers beträgt standardmäßig 8 kb. Sie deaktivieren die Pufferung, wenn Sie wollen, oder einfach nur die Größe des Puffers ändern, mit der Eigenschaft

ServerProperties.OUTBOUND_CONTENT_LENGTH_BUFFER

Ein Integer-Wert, der die Puffergröße definiert verwendet serverseitige Antworteinheit zu puffern, um zu Bestimmen Sie seine Größe und legen Sie den Wert des Headers HTTP "Content-Length" fest.

Wenn die Entitätsgröße die konfigurierte Puffergröße überschreitet, wird die Pufferung abgebrochen und die Entitätsgröße wird nicht ermittelt. Wert kleiner oder gleich Null deaktiviert die Pufferung der Entität überhaupt.

Diese Eigenschaft kann auf der Serverseite verwendet werden, um den Wert der Puffergröße für ausgehende Nachrichten zu überschreiben - Standard oder den globalen benutzerdefinierten Wert, der über die globale Eigenschaft "jersey.config.contentLength.buffer" festgelegt wird.

Der Standardwert ist 8192.

ein Beispiel Hier ist

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

Hier das Ergebnis ohne die Eigenschaft Einstellung

enter image description here

Und hier ist das Ergebnis, nachdem die Eigenschaft festlegen Wert zu 0

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

enter image description here

+0

Dies ist eine großartige Lösung. Eine Sache, die ich gerade gefunden habe - das funktioniert nur, wenn Sie am Ende Ihrer Eingabe einen Zeilenumbruch haben :) – pandaadb

1

Try outputStream.flush() aus dem Verfahren FeedReturnStreamingOutput.write(...) jedes X Anzahl der geschriebenen Bytes in den Ausgabestream oder so etwas aufruft.

Ich denke, der Puffer der Verbindung nicht mit den Daten, die Sie zurückkommen gefüllt ist. Der Service gibt also nichts zurück, bis Jersey outputStream.close() aufruft.

In meinem Fall habe ich einen Dienst, der Daten streamt und ich mache es genau so wie Sie: indem Sie Response.ok(<instance of StreamingOutput>).build(); zurückgeben.

Mein Service gibt Daten aus einer Datenbank und rufe ich outputStream.flush() nach jeder Zeile in den Ausgabestream zu schreiben.

Ich weiß, dass die Service-Datenströme, weil ich die Client-Daten sehen beginnt mit dem Empfang, bevor der Dienst das gesamte Ergebnis Senden beendet hat.

+0

I hinzugefügt outputstream.flush jedesmal I in den Ausgabestrom zu schreiben. Macht keinen Unterschied – PrabhaT

+0

@ user1016496 Woher wissen Sie, dass der Dienst nicht streamt? Könnte es sein, dass der Dienst die Daten tatsächlich streamt, aber der Client nicht schreibt, was er im Streaming-Modus erhält? – Montecarlo

1

Entweder Ihre Antwort ist zu klein und wird nie chunked so dass der Server die gesamte Meldung auf einmal spült. Oder Sie haben ein serverseitiges Problem, wenn Ihre jax-rs-Bibliothek darauf wartet, den vollständigen Stream vor dem Leeren zu haben.

Allerdings sieht dies eher wie ein Client-Problem aus. Und Sie scheinen eine alte Version von Jersey-Client zu verwenden.

auch, dass .get(ClientResponse.class) sieht verdächtig aus.

Versuchen Sie, den JAX-RS unter Verwendung von Standard wie heute (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(); 

Während mit Jersey-Client 2.17 im Classpath:

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

Ich habe erkannt, dass, wenn Sie eine verwenden Unterklasse von StreamingOutput, Jersey streamen nicht die Antwort:

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

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

Ist das ein Jersey-Käfer?

+0

Was meinst du "wie erwartet"? –

+0

Ich meinte Stream die Antwort. Ich werde die Antwort aktualisieren. –

+0

Ich glaube nicht, dass das das Problem ist. Alles ist [der Schreiber] (https://github.com/jersey/jersey/blob/master/core-common/src/main/java/org/glassfish/jersey/message/internal/StreamingOutputProvider.java#L75) Rufen Sie Ihre 'write' Methode auf und übergeben Sie die Entity OutputStream. Nichts Besonderes geht weiter. Das Streaming-Problem ist mit dem Pufferausgangsstrom, den Jersey verwendet, um die Inhaltslänge zu zählen. Du kannst dies mit [dieser Eigenschaft] (https://jersey.java.net/apidocs/2.22/jersey/org/glassfish/jersey/server/ServerProperties.html#OUTBOUND_CONTENT_LENGTH_BUFFER) auf 0 setzen. –