2017-11-20 2 views
0

Ich möchte in der Lage sein, die tatsächliche Größe der Web-Server-Antwort Körper zu erfassen, wie ich Dinge mit OkHttp (für Überwachungszwecke) abholen.Aufnahme OkHttp Antwort Körpergröße, ohne die ganze Sache zu puffern

Gibt es eine Möglichkeit, die tatsächliche Größe des Antwortkörpers (beachten Sie - nicht die vom Server beanspruchte Länge des Inhalts) ohne die Kosten der Pufferung der gesamten Antwort in den Speicher?

+0

Aber der Server hat Recht über die ContentLength, oder? Sehen Sie sich dieses Dokument an: https://square.github.io/okhttp/3.x/okhttp/okhttp3/ResponseBody.html – rafid059

+0

Nun, der Server liefert möglicherweise überhaupt keine Inhaltslänge, weil der Inhalt von irgendwo gestreamt wird unbestimmte Länge (dh der Fall, in dem ResponseBody.contentLength -1 zurückgibt) ... Aber es ist auch nicht unbedingt mein Server, und es könnte in der Tat falsche Längenheader zurückgeben (obwohl okhttp das irgendwie irgendwie verbieten wird). –

+0

Ah, habe es noch nicht richtig verdaut, aber es sieht so aus, als ob das readTwice-Zeug von https://gist.github.com/digitalbuddha/3c5bb15fa12a553c85ec ein Weg sein könnte (wo der zweitgelesene Teil nur die Länge zählt) von den Daten, die es gesehen hat und den tatsächlichen Inhalt ignorierend). –

Antwort

0

Diese für scheint zu funktionieren, was ich wollte ...

AtomicLong bytesRead = new AtomicLong(); 

OkHttpClient client = new OkHttpClient.Builder().addNetworkInterceptor(new Interceptor() { 

    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Response response = chain.proceed(chain.request()); 

     response = response.newBuilder() 
      .body(
       new RealResponseBody(
        response.body().contentType().toString(), 
        response.body().contentLength(), 
        Okio.buffer(
         new LengthTrackingSource(
          response.body().source(), 
          (newBytesRead) -> { 
           bytesRead.addAndGet(newBytesRead); 
          } 
         ) 
        ) 
       ) 
      ) 
      .build(); 

     return response; 
    } 

    class LengthTrackingSource implements Source { 

     private Source source; 


     private Consumer<Long> lengthRecorder; 

     public LengthTrackingSource(Source source, Consumer<Long> lengthRecorder) { 
      this.source = source; 
      this.lengthRecorder = lengthRecorder; 
     } 

     @Override 
     public long read(Buffer sink, long byteCount) throws IOException { 
      long bytesRead; 
      try { 
       bytesRead = source.read(sink, byteCount); 
      } catch (IOException e) { 
       throw e; 
      } 

      // Avoid adding the final -1 (which means the source is exhausted) 
      if (bytesRead > 0) { 
       lengthRecorder.accept(bytesRead); 
      } 

      return bytesRead; 
     } 

     @Override 
     public Timeout timeout() { 
      return source.timeout(); 
     } 

     @Override 
     public void close() throws IOException { 
      source.close(); 
     } 
    } 

}).build(); 

try (Response response = client.newCall(new Request.Builder().url("http://example.com/").build()).execute()) { 
    System.out.println(bytesRead.get()); 

    String body = response.body().string(); 
    System.out.println(body.length()); 

    System.out.println(bytesRead.get()); 
} 

Wenn es eine einfachere Weise, die ich immer noch davon hören würde gerne!

Verwandte Themen