Accessing body string of an OkHttp Response twice results in IllegalStateException: closed

degill picture degill · Jan 13, 2015 · Viewed 15.5k times · Source

I implement my http calls via the OkHttp library. Everything works fine, but I noticed that, when I access the body as a string of the response twice an IllegalStateException will be thrown. That is, I do (for example): Log.d("TAG", response.body().string()) and after that I actually want to use that string like processResponse(response.body().string()). But that second call throws the exception with the message closed.

How can it be possible that accessing a string twice results in a failure? I want to process that response without the need to add a wrapper/dummy object just for saving some values (like header, body, statuscode).

Answer

Peter F picture Peter F · Nov 23, 2015

Update:

As mugwort points out there is a simpler, more lightweight API available now (see GitHub issue):

String responseBodyString = response.peekBody(Long.MAX_VALUE).string();
Log.d("TAG", responseBodyString);

Original Answer:

For explanation of the issue see Greg Ennis' answer.

However, if you can not easily pass the result in a variable, but still need to access the response body twice you have another option:

Clone the buffer before reading it. By that the original buffer is neither emptied nor closed. See this snippet:

ResponseBody responseBody = response.body();
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // request the entire body.
Buffer buffer = source.buffer();
// clone buffer before reading from it
String responseBodyString = buffer.clone().readString(Charset.forName("UTF-8"))
Log.d("TAG", responseBodyString);

This approach is used in HttpLoggingInterceptor in project okhttp by square themselves.