我通过OkHttp库实现我的http调用。一切都很好,但我注意到,当我作为一个响应的字符串两次访问身体时,将抛出IllegalStateException
。也就是说,我(例如):Log.d("TAG", response.body().string())
,之后我实际上想要使用像processResponse(response.body().string())
那样的字符串。但是第二次调用抛出了closed
消息的异常。
怎么可能两次访问字符串导致失败?我想处理该响应而不需要添加包装器/虚拟对象只是为了保存一些值(如header,body,statuscode)。
响应中的string
方法将读取输入(网络)流并将其转换为字符串。所以它动态构建字符串并将其返回给您。第二次调用它时,网络流已经被消耗并且不再可用。
您应该将string
的结果保存到String变量中,然后根据需要多次访问它。
更新:
作为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中被广场本身使用。
顺便说一句,除了格雷格恩尼斯的回答之外,当我在观察窗口忘记了response.body()。string()时,我可以告诉我发生了什么事。因此,在调试器下,正在读取监视器,然后关闭网络流。
您可以调用response.peekBody(Long.MAX_VALUE);
来缓冲内存中的整个响应,并获得它的轻量级副本。它会减少浪费。 See this issue on GitHub。
ResponseBody body = response.peekBody(Long.MAX_VALUE);
String content = body.string();
//do something
此代码获取响应正文,不会消耗缓冲区。这是在this issue添加的新api
在user2011622和Greg Ennis的答案上稍微扩展一下,我创建了一个方法,可以帮助您创建一个完整的身体克隆,允许您分别使用身体的每个副本。我自己用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);
}
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();
}
}