OkHttp请求回调中response.body().string()只能有效调用一次,为什么呢?
- reponse.body()只能被调用一次?
- reponse.body().string()只能被调用一次!
一、reponse.body()只能被调用一次?
很多人以为reponse.body()只能被调用一次,其实不然。
请看Okhttp源码中的Response.java文件的body()实现。
/**
* Returns a non-null value if this response was passed to {@link Callback#onResponse} or returned
* from {@link Call#execute()}. Response bodies must be {@linkplain ResponseBody closed} and may
* be consumed only once.
*
* <p>This always returns null on responses returned from {@link #cacheResponse}, {@link
* #networkResponse}, and {@link #priorResponse()}.
*/
public ResponseBody body() {
return body;
}
很显然,body()只是简单的返回了ResponseBody。
body的定义如下:
final ResponseBody body;
看看body()方法的注释吧,也许能发现点什么?翻译为中文如下:
/**
* 返回一个非空的值,如果这个反应是通过回调方法onResponse()或execute()方法返回。
* 响应体必须关闭,并且可能只能消耗一次。
* 如果响应体来自cacheresponse,networkresponse,priorresponse(),body()方法将总是返回null
*/
可以看到,这里只是告诉你响应体必须被关闭,但是这里并没有做这个操作。
它告诉你响应体可能只能被消耗一次,大概是因为响应体被消耗一次后必须关闭吧。
二、reponse.body().string()只能被调用一次!
为什么说,reponse.body().string()只能被调用一次!
请看Okhttp源码中的ResponseBody.java文件的string()实现。
/**
* Returns the response as a string decoded with the charset of the Content-Type header. If that
* header is either absent or lacks a charset, this will attempt to decode the response body in
* accordance to <a href="https://en.wikipedia.org/wiki/Byte_order_mark">its BOM</a> or UTF-8.
* Closes {@link ResponseBody} automatically.
*
* <p>This method loads entire response body into memory. If the response body is very large this
* may trigger an {@link OutOfMemoryError}. Prefer to stream the response body if this is a
* possibility for your response.
*/
public final String string() throws IOException {
BufferedSource source = source();
try {
Charset charset = Util.bomAwareCharset(source, charset());
return source.readString(charset);
} finally {
Util.closeQuietly(source);
}
}
可以看到执行完string()方法后,IO流必须被关闭。
Util.closeQuietly(source);
由此可知,string()方法只能调用一次,调用一次后响应体就失效了。
Closes {@link ResponseBody} automatically.
另外,由注释可知,string()方法会根据header中Content-Type返回对应编码的字符串,如果没有该属性则返回BOM或者UTF-8编码的字符串
再者,由注释可知,string()方法会把响应体的内容加载在内存中,如果响应体内容非常大,将会引发OutOfMemoryError异常,因此最好用流的方式去获取响应体。