访问OkHttp Response的正文字符串两次会导致IllegalStateException:closed

时间:2015-01-13 12:54:09

标签: android okhttp

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

两次访问字符串怎么可能导致失败?我想处理该响应而不需要添加包装器/虚拟对象只是为了保存一些值(如header,body,statuscode)。

7 个答案:

答案 0 :(得分:54)

<强>更新

作为mugwort points out,现在有一个更简单,更轻量级的API(see GitHub issue):

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

原始答案:

有关此问题的说明,请参阅Greg Ennis' answer

但是,如果您无法轻松地将结果传递给变量,但仍需要访问响应主体两次,则还有另一个选项:

在读取之前克隆缓冲区。由此原始缓冲区既不清空也不关闭。请参阅以下代码段:

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

此方法在项目HttpLoggingInterceptor中的okhttp中用于平方。

答案 1 :(得分:35)

响应上的string方法将读取输入(网络)流并将其转换为字符串。所以它动态构建字符串并将其返回给您。第二次调用它时,网络流已经被消耗并且不再可用。

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

答案 2 :(得分:3)

除了格雷格·恩尼斯的回答之外,我还可以告诉我,当我在观察窗口中忘记了response.body()。string()时,我发生了什么事。因此,在调试器下,正在读取监视器,然后关闭网络流。

答案 3 :(得分:1)

您可以调用response.peekBody(Long.MAX_VALUE);将整个响应缓冲在内存中并获得其轻量级副本。这样会减少浪费。 See this issue on GitHub

答案 4 :(得分:1)

ResponseBody body = response.peekBody(Long.MAX_VALUE);
String content = body.string();
//do something

此代码获取响应主体,并且不会占用缓冲区。它是this issue

中添加的新API

答案 5 :(得分:0)

user2011622Greg Ennis的答案上稍微扩展一下,我创建了一个方法,可以帮助您创建一个完整的正文克隆,允许您分别使用正文的每个副本。我自己使用这种方法和Retrofit2

Viewbox

答案 6 :(得分:-1)

            if (response.isSuccessful()) {

                Gson gson = new Gson();
                String successResponse = gson.toJson(response.body());
                Log.d(LOG_TAG, "successResponse: " + successResponse);

            } else {

                try {
                    if (null != response.errorBody()) {
                        String errorResponse = response.errorBody().string();
                        Log.d(LOG_TAG, "errorResponse: " + errorResponse);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }