访问OkHttp响应的主体string两次导致IllegalStateException:closures

我通过OkHttp库实现了我的http调用。 一切工作正常,但我注意到,当我作为响应的string访问身体两次IllegalStateException将被抛出。 也就是说,我做(例如): Log.d("TAG", response.body().string())之后,我真的想使用像processResponse(response.body().string()) 。 但是,第二个调用会抛出closed消息的exception。

如何访问string两次导致失败? 我想处理该响应,而不需要添加一个包装/虚拟对象只是为了保存一些值(如标题,正文,状态码)。

Solutions Collecting From Web of "访问OkHttp响应的主体string两次导致IllegalStateException:closures"

响应中的string方法将读取input(networking)stream并将其转换为string。 所以它dynamic地build立string并将其返回给你。 第二次调用它时,networkingstream已经被使用,不再可用。

您应该将string的结果保存到一个stringvariables中,然后根据需要多次访问它。

有关问题的解释,请参阅Greg Ennis的回答 。

但是,如果您不能轻易地将结果传递给variables,但仍需要访问响应正文两次,则还有另一个选项:

在读取之前先克隆缓冲区。 由此,原缓冲区既不清空也不closures。 看到这个片段:

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

这个方法用在okhttp项目中的HttpLoggingInterceptor中 。

顺便说一句,除了格雷格·恩尼斯的回答,我可以告诉什么时候发生了什么,当我忘记response.body()。string()在观察窗口。 所以在debugging器下面,身体正在读入手表,然后networkingstream被closures。

在user2011622和Greg Ennis的回答中稍微扩展了一下,我创build了一个方法,可以帮助您创build一个完整的身体克隆,允许您分别消耗身体的每个副本。 我用Retrofit2自己使用这个方法

 /** * Clones a raw buffer so as not to consume the original * @param rawResponse the original {@link okhttp3.Response} as returned * by {@link Response#raw()} * @return a cloned {@link ResponseBody} */ private ResponseBody cloneResponseBody(okhttp3.Response rawResponse) { final ResponseBody responseBody = rawResponse.body(); final Buffer bufferClone = responseBody.source().buffer().clone(); return ResponseBody.create(responseBody.contentType(), responseBody.contentLength(), bufferClone); }