1 Retrofit
简介
A type-safe HTTP client for Android and Java
Retrofit
是一个网络请求框架的封装,底层网络请求默认使用OkHttp
,也就是说Retrofit
本身并不具备网络请求的能力,只是简化了网络请求的相关参数配置或者说Retrofit
只负责上层接口的封装。
使用Retrofit
,实际上是使用Retrofit
接口层封装请求参数、Header
、Url
等信息,之后由OkHttp
完成后续的请求操作,当服务端返回数据之后,OkHttp
再将原始的结果交给Retrofit
,然后Retrofit
根据用户的需求,对结果进行解析。
Retrofit
不仅具备了OkHttp
的高效性,还有以下优势:
- 支持
RESTful API
设计风格; - 通过注解配置请求:包括请求方式、请求参数、请求头、返回值等
- 可以搭配多种
Converter
(转换器)将获得的数据自动解析和序列化:支持Gson
、Jackson
、Protoful
等 - 提供了对
RxJava
的支持
converter [kənˈvɜːrtər] 转换器;整流器;变频器;转换程序;变焦镜
RESTful API
:
REST (Respresentational State Transfer)
,表述性状态转移;REST
只是风格而没有标准,其核心是一切皆资源。这里的资源不一定只是数据,而是数据加表现形式的组合。任何可命名的抽象概念都可以定义为一个资源;- 符合
REST
风格的API
就可以叫做RESTful API
比如说,如果要访问https://xxxx/user/10000/info
,对应的找到userId
为10000
的这条用户的数据:
// GET、POST、PUT、DELETE
@GET("/user/{userId}/info")
Call<UserInfo> getUserInfo(@Path("userId") String userId)
RESTful
对资源操作:
POST
:用于在服务器中新建一个资源,对应资源操作是INSERT
,非幂等且不安全;DELETE
:用于从服务器删除资源,对饮的资源是DELETE
,幂等且不安全;PUT
:用于在服务器中更新资源,客户端提供改变后的完整资源,对应资源操作是UPDATE
,幂等且不安全;GET
:用于从服务器中取出资源,对应资源操作是SELETE
,幂等且安全;
2 Retrofit
的设计思想
Retrofit
的设计基于以下几个事实:同一款应用中的网络请求绝大多数指向的是同一个服务器域名。因为在大多数的情况下,客户端和服务器的数据都是配套使用的。另外,服务器提供的接口通常是可以根据功能来归类的。比如新增用户、修改用户数据、查询用户数据这几个接口就可以归为一类,上架新书、销售图书、查询可供销售图书这几个接口也可以归为一类。将服务器接口合理归类能够让代码结构变得更加合理,从而提高可阅读性和可维护性。最后,开发者肯定更加习惯于“调用一个接口,获取它的返回值”这样的编码方式,大多数人并不关心网络的具体通信细节,但是传统网络库的用法却需要编写太多网络相关的代码。
而Retrofit
的用法就是基于以上几点来设计的,首先配置好一个根路径,然后在指定服务器接口地址时只需要使用相对路径即可,这样就不用每次都指定完整的URL
地址了。另外,Retrofit
允许我们对服务器接口进行归类,将功能同属一类的服务器接口定义到同一个接口文件当中,从而让代码结构变得更加合理。
最后,我们也完全不用关心网络通信的细节,只需要在接口文件中声明一系列方法和返回值, 然后通过注解的方式指定该方法对应哪个服务器接口,以及需要提供哪些参数。当我们在程序中调用该方法时,Retrofit
会自动向对应的服务器接口发起请求,并将响应的数据解析成返回值声明的类型。这就使得我们可以用更加面向对象的思维来进行网络操作。
3 Retrofit
的基本用法
想使用Retrofit
,需要先在项目中添加必要的依赖库。在app/build.gradle
文件中添加如下内容:
dependencies {
...
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
}
由于Retrofit
是基于OkHttp
开发的,因此添加第一条依赖时,会自动将Retrofit
、OkHttp
和Okio
这几个库一起下载,无须再手动引入OkHttp
库。另外,Retrofit
还会将服务器返回的JSON
数据自动解析成对象,因此上述第二条依赖就是一个Retrofit
的转换库,它是借助GSON
来解析GSON
数据的,所以会自动将GSON
库一起下载下来,这样我们也不用手动引入GSON
库 了。除了GSON
之外,Retrofit
还支持各种其他主流的JSON
解析库,包括Jackson
、Moshi
等, 不过毫无疑问GSON
是最常用的。
由于Retrofit
会借助converter-gson
将JSON
数据转换成对象,因此需要定义一个User
类,如下所示:
class User(val id: Int, val username: String, val mobile: String)
接下来,根据服务器接口的功能进行归类,创建不同种类的接口文件,并在其中定义对应具体服务器接口的方法。新建ApiService
接口,代码如下所示:
interface ApiService {
@FormUrlEncoded
@POST("login")
fun login(@Field("username") username: String, @Field("password") password: String)
: Call<ResponseBody>
}
通常Retrofit
的接口文件建议以具体的功能种类名开头,并以Service
结尾,这是一种比较好的命名习惯。
上述代码中有两点需要注意。第一就是在login
方法上面添加的注解,这里使用 了一个@POST
和@FormUrlEncoded
注解,表示当调用login
方法时Retrofit
会发起一条POST
请求,请求的地址就是在@POST
注解中传入的具体参数。注意,这里只需要传入请求地址的相对路径即可,根路径会在稍后设置。
第二就是login
方法的返回值必须声明成Retrofit
中内置的Call
类型,并通过泛型来指定服务器响应的数据应该转换成什么对象。由于服务器响应的是一个包含ResponseBody
数据的JSON
数据,因此这里将泛型声明成ResponseBody
。当然,Retrofit
还提供了强大的Call Adapters
功能来允许我们自定义方法返回值的类型,比如Retrofit
结合RxJava
使用就可以将返回值声明成Observable
、Flowable
等类型。
定义好了ApiService
接口之后,接下来的问题就是该如何使用它:
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
val apiService = retrofit.create(ApiService::class.java)
apiService.login("admin", "1123456").enqueue(object : retrofit2.Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>, response: Response<ResponseBody>) {
val result = response.body()?.string()
}
override fun onFailure(call: Call<ResponseBody>, t: Throwable) {
t.printStackTrace()
}
})
首先使用了Retrofit.Builder
来构建 一个Retrofit
对象,其中baseUrl
方法用于指定所有Retrofit
请求的根路径, addConverterFactory()
方法用于指定Retrofit
在解析数据时所使用的转换库,这里指定成GsonConverterFactory
。注意这两个方法都是必须调用的。
有了Retrofit
对象之后,就可以调用它的create()
方法,并传入具体Service
接口所对应的Class
类型,创建一个该接口的动态代理对象。有了动态代理对象之后,就可以随意调用接口中定义的所有方法,而 Retrofit
会自动执行具体的处理就可以了。
对应到上述的代码当中,当调用了ApiService
的login
方法时,会返回一个 Call<ResponseBody>
对象,这时再调用一下它的enqueue()
方法,Retrofit
就会根据注解中配置的服务器接口地址去进行网络请求了,服务器响应的数据会回调到enqueue()
方法中传 入的Callback
实现里面。需要注意的是,当发起请求的时候,Retrofit
会自动在内部开启子线程,当数据回调到Callback
中之后,Retrofit
又会自动切换回主线程,整个操作过程中我们都不用考虑线程切换问题。在Callback
的onResponse()
方法中,调用response.body()
方法将会得到Retrofit
解析后的对象,也就是ResponseBody
类型的数据。
Retrofit
的基本使用流程:
- 通过建造者模式构建一个
Retrofit
实例; - 通过
Retrofit
对象的create
方法创建接口实例(动态代理); - 调用接口的方法解析注解,调用具体的网络请求方法;
- 通过数据解析器解析数据;
- 调用回调执行器,切换线程,处理返回结果;
动态代理:运行时创建的代理类,在委托类的方法前后去做一些事情。在运行过程中,会在虚拟机内部创建一个Proxy
的类。通过实现InvocationHandler
的接口,来代理委托类的函数。使用动态代理来对接口中的注释进行解析,解析后完成OkHttp
的参数构建。这样做的好处是代理类原始类脱离联系,在原始类和接口未知的时候就确定代理类的行为。 以下是相关源码:
public final class Retrofit {
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
}
Retrofit
的基本使用流程很简洁,其内部使用了优秀的架构设计和大量的设计模式。比如,Retrofit
构建过程会用到建造者模式、工厂方法模式,建网络请求接口实例过程会用到外观模式、代理模式、单例模式、策略模式、装饰模式(建造者模式),生成并执行请求过程适配器模式(代理模式、装饰模式)。
4 Retrofit
构造器的最佳写法
学到这里,有一个问题就是获取Service
接口的动态代理对象实在是太麻烦了。先回顾一下之前的写法,大致代码如下所示:
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
想要得到ApiService
的动态代理对象,需要先使用Retrofit.Builder
构建出一个Retrofit
对象,然后再调用Retrofit
对象的create()
方法创建动态代理对象。如果只是写一次还好,每次调用任何服务器接口时都要这样写一遍的话,是很繁琐的。
事实上,确实没有每次都写一遍的必要,因为构建出的Retrofit
对象是全局通用的,只需要在调用create()
方法时针对不同的Service
接口传入相应的Class
类型即可。因此,可以将通用的这部分功能封装起来,从而简化获取Service
接口动态代理对象的过程。
新建一个ServiceCreator
单例类,代码如下所示:
object ServiceCreator {
private val BASE_URL = "http://10.0.2.2"
private val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
fun <T> create(serviceClass: Class<T>): T = retrofit.create(serviceClass)
}
这里使用object
关键字让ServiceCreator
成为了一个单例类,并在它的内部定义了一 个BASE_URL
常量,用于指定Retrofit
的根路径。然后同样是在内部使用Retrofit.Builder
构建一个Retrofit
对象,注意这些都是用private
修饰符来声明的,相当于对于外部而言它们都是不可见的。
最后,提供了一个外部可见的create()
方法,并接收一个Class
类型的参数。当在外部调用这个方法时,实际上就是调用了Retrofit
对象的create()
方法,从而创建出相应Service
接口的动态代理对象。
经过这样的封装之后,Retrofit
的用法将会变得异常简单,比如我们想获取一个Appiervice
接口的动态代理对象,只需要使用如下写法即可:
val apiService = ServiceCreator.create(ApiService::class.java)
之后就可以随意调用ApiService
接口中定义的任何方法了。
5 源码分析
Retrofit
使用建造者模式来创建实例,之后在Retrofit.create
方法中使用动态代理技术创建接口(ApiService
)的实现类,将接口(ApiServie
)中的方法调用集中到InvocationHandler.invoke
方法中。
建造者模式主要是用来构建灵活性和扩张性较强的复杂对象。
代理模式是通过代理对象访问目标对象,这样做的好处是可以通过代理对象扩展目标对象的功能。静态代理在程序运行前就已经将代理的源码编译成字节码文件,代理类和目标类的关系在运行前就已经确定了。动态代理是在程序运行期间由JVM
根据反射原理等机制动态生成的,所以不会有代理类的字节码文件,代理类和目标类的关系是在程序运行时确定的。动态代理的好处就是更加灵活,更适用于处理目标对象不固定的情况(接口不固定,当作参数传入)。
Java
的反射机制是在程序运行期间,对于任意一个类,都知道这个类的属性和方法,对于任意一个对象都能都能够调用它的属性和方法。
在InvocationHandler.invoke
方法中调用了Retrofit.loadServiceMethod(method)
方法来获取ServiceMethod
,ServiceMethod
的职责主要是解析它对应的method
的各种参数,比如注解,而解析过程是在ServiceMethod
的创建过程中产生的,这就导致ServiceMethod
的创建既耗时又耗费资源,所以为ServiceMethod
创建了缓存来提高效率。
在ServiceMethod.parseAnnotations(this, method)
方法通过RequestFactory
解析注解,然后返回RequestFactory
对象,接着把解析的requestFactory
、retrofit
、method
传入到HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
方法中。HttpServiceMethod
是抽象类ServiceMethod
的子类,并实现了ServiceMethod
的抽象方法ServiceMethod.invoke
方法。
在HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
方法中会获取okhttp3.Call.Factory.callFactory
、callAdapter
、responseConverter
等Retrofit
的配置,为后面创建的retrofit2.OkHttpCall
做参数配置。其中callFactory
是OkHttpClient
对象,是在Retrofit.build
方法中创建的。
在HttpServiceMethod.invoke
方法中会创建retrofit2.OkHttpCall
实例,而在retrofit2.OkHttpCall
中实际上是使用okhttp3.Call
进行网络请求,requestFactory
也会用来构造okhttp3.Call
对象。在网络请求成功后找到对应的转换器来解析数据。
annotation [ˌænəˈteɪʃ(ə)n] 注释,评注;注释,加注
以下是相关源码:
Retrofit
使用建造者模式来创建实例,之后在Retrofit.create
方法中使用动态代理技术创建接口(ApiService
)的实现类,将接口(ApiServie
)中的方法调用集中到InvocationHandler.invoke
方法中:
public final class Retrofit {
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
}
在InvocationHandler.invoke
方法中调用了Retrofit.loadServiceMethod(method)
方法来获取ServiceMethod
,ServiceMethod
的职责主要是解析它对应的method
的各种参数,比如注解,而解析过程是在ServiceMethod
的创建过程中产生的,这就导致ServiceMethod
的创建既耗时又耗费资源,所以为ServiceMethod
创建了缓存来提高效率:
public final class Retrofit {
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
}
在ServiceMethod.parseAnnotations(this, method)
方法通过RequestFactory
解析注解,然后返回RequestFactory
对象,接着把解析的requestFactory
、retrofit
、method
传入到HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
方法中。HttpServiceMethod
是抽象类ServiceMethod
的子类,并实现了ServiceMethod
的抽象方法ServiceMethod.invoke
方法:
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
...
}
在HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory)
方法中会获取okhttp3.Call.Factory callFactory
、callAdapter
、responseConverter
等Retrofit
的配置,为后面创建的retrofit2.OkHttpCall
做参数。其中callFactory
是OkHttpClient
对象,是在Retrofit.build
方法中创建的:
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(
method,
"'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>)
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
private final CallAdapter<ResponseT, ReturnT> callAdapter;
CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) {
super(requestFactory, callFactory, responseConverter);
this.callAdapter = callAdapter;
}
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
}
}
public final class Retrofit {
public static final class Builder {
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
}
}
在HttpServiceMethod.invoke
方法中会创建retrofit2.OkHttpCall
实例,而在retrofit2.OkHttpCall
中实际上是使用okhttp3.Call
进行网络请求,requestFactory
也会用来构造okhttp3.Call
对象。在网络请求成功后找到对应的转换器来解析数据:
final class OkHttpCall<T> implements Call<T> {
private final RequestFactory requestFactory;
private final Object[] args;
private final okhttp3.Call.Factory callFactory;
private final Converter<ResponseBody, T> responseConverter;
OkHttpCall(
RequestFactory requestFactory,
Object[] args,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, T> responseConverter) {
this.requestFactory = requestFactory;
this.args = args;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
}
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = getRawCall();
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse =
rawResponse
.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
rawBody.close();
return Response.success(null, rawResponse);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
}
参考
https://zhuanlan.zhihu.com/p/421401880