Retrofit和OkHttp的一些常用配置总结

Retrofit 和 OkHttp 是现在常用的网络框架,在处理复杂的网络请求方面极大地简化了开发者的工作。下面总结下自己在开发过程中常用的配置。用到的Retrofit版本为2.2,OkHttp版本为3.6。

1
2
3
compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'

Retrofit 2 中已经集成了 OkHttp,所以只要导入 Retrofit 就行了。主要就是对 OkHttpClient 进行配置,因为网络请求的底层实现主要靠它,Retrofit 只是做了上层封装。

1
2
3
4
5
6
7
8
9
10
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
/**
* 对clientBuilder的具体的配置
*/
OkHttpClient okHttpClient = clientBuilder.build();
retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.57.1:5656/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();

在所有的请求头部附上token

1
2
3
4
5
6
7
8
9
10
public class TokenInterceptor implements Interceptor{
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
request = request.newBuilder()
.addHeader("Authorization",App.token)
.build();
return chain.proceed(request);
}
}

clientBuilder.addInterceptor(new TokenInterceptor());
在关系到用户操作时经常在请求中附上 token , 如果一个个在每个请求中加 token 肯定是不够优雅的,万一哪一天验证方式变了是不是还要一个个去改呢?所以 OkHttp 就提供了 Interceptor 这个接口让我们去实现对每个请求进行拦截操作,修改自定义请求参数,还可以添加多个 Interceptor ,分别用作不同的用途,方便维护。这很像 Node.js 中的中间件思想,在正式处理响应回复前交由这些 Interceptor 拦截处理,然后一个个往下传递,最终把 response 传给业务逻辑层。

如果访问多个地址的异常处理有着相同的逻辑,也不妨把它放在 Interceptor 中进行处理,就不用每次都在 onResponse 方法里面判断返回状态码在进行处理,onResponse 里面直接是正常情况下返回的数据。

在 token 过期时刷新 token

1
2
3
4
5
6
7
8
9
10
11
public class TokenAuthenticator implements Authenticator{
@Override
public Request authenticate(Route route, Response response) throws IOException {
String newToken = RetrofitFactory.getRetrofit().login(App.sUser).execute().body()
.data.token;
UserStorge.getInstance().setToken(newToken);
return response.request().newBuilder()
.header("Authorization", newToken)
.build();
}
}

clientBuilder.authenticator(new TokenAuthenticator());
这种方式是官方推荐的方式,需要在接收到 401 状态码时才会调用 authenticate 方法,执行时首先就是获取新的 token,这里我采用重新登录的方式获取最新的 token,然后再把新的 token 更新至刚才的请求中。在这中间还可以保存新的 token 到本地,方便下次使用。如果服务端在 token 失效时不是返回的401,而是在 body 里面有字段标识,那就只能用 Interceptor 进行处理。

添加网络日志打印

1
2
3
4
5
6
if(BuildConfig.DEBUG){
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
clientBuilder.addInterceptor(loggingInterceptor);
}

在开发调试时开启网络请求日志打印,打印的详略可以自己设置。

开启缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class RewriteInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
String cacheControl = originalResponse.header("Cache-Control");
//改写缓存设置,因为服务器端一般不会设置 Cache-Control ,当前配置为10秒内再次请求则使用缓存。
if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains(
"no-cache") ||
cacheControl.contains("must-revalidate") || cacheControl.contains("max-age=0")) {
return originalResponse.newBuilder()
.header("Cache-Control", "public, max-age=" + 10)
.build();
} else {
return originalResponse;
}
}
}
public class OfflineInterceptor implements Interceptor{
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetUtils.isNetWorkAvailable()) {
//允许读取过期时间小于 maxStale 的缓存
int maxStale = 60 * 60 * 24 * 7;
request = request.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
return chain.proceed(request);
}
}
File httpCacheDirectory = new File(App.sContext.getCacheDir(), "responses");
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(httpCacheDirectory, cacheSize);
clientBuilder.addNetworkInterceptor(new RewriteResponseInterceptor())
.addInterceptor(new OfflineInterceptor())
.cache(cache);

开启OkHttp的缓存配置可以减少服务器端的压力,同时在离线环境下也能有较好的用户体验,能保留上次请求过的内容。缓存机制只支持 GET 请求,根据具体情况可自定义不同的缓存策略。

以上就是常用的网络配置,灵活运用 Interceptor 就是其中的关键所在。