Retrofit可以与Gson很好的结合,直接以Call<***Entity>的方式更加便捷的形式返回给我们。
但我们也需要出关心服务器的返回数据,以便我们更好的开发,比如
- 和服务器联调接口,要随时知道服务器都返回了什么
- Gson解析报错了,可能是只是一样解析出错的Log,但我们想知道服务器返回了什么样的数据结构(或者是json的内容)。
- 等等
…
这个时候我们就需要使用我们接下来介绍的内容, 拦截器
拦截器
除了上述那个场景,还可以做哪些呢? 那我们就来统计一下拦截器的日常使用吧:
- 日志Log打印
- 缓存设置
- 请求头处理
日志Log打印
Retrofit的网络请求部分是由Okhttp来负责的,所以我们需要添加拦截器的地方也就是在okHttp中。
拦截器我们可以使用sdk提供的,也可以自己自定义拦截器,这样更加灵活一些。
- 使用OkHttp中的日志拦截器。
导入下面依赖
implementation ‘com.squareup.okhttp3:logging-interceptor:3.4.1’
如何使用呢?
OkHttpClient.Builder builder = new OkHttpClient()
.newBuilder()
.connectTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS)
.readTimeout(READ_TIME_OUT, TimeUnit.SECONDS)
.addInterceptor(new HeaderInterceptor());
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(interceptor);
}
注意
- BuildConfig.DEBUG 这里的逻辑判断是必须要添加的
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
这里的日志类别可以为 NONE
,BASIC
,HEADERS
,BODY
这样就ok了。日志可以正常打印了。
- 自定义Interceptor
我们需要继承Interceptor
并实现intercept
方法
实现也比较简单,可以通过 Chain chain
中获取我们需要的 Request、Response
那我们就可以为所欲为了~~~!
private class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Log.e(TAG," ------------------------------------------------------------------");
Request request = chain.request(); // 获取到我们的请求封装对象
long requestTime = System.currentTimeMillis(); // 发起时间
HttpUrl url = request.url();
Headers headers = request.headers();
Log.e(TAG,"request Url : "+url);
Log.e(TAG,"request Headers : "+headers);
Response response = chain.proceed(chain.request());
long responseTime = System.currentTimeMillis();
boolean successful = response.isSuccessful();
HttpUrl responseUrl = response.request().url();
long contentLength = response.body().contentLength();
//此处本来是想用 contentLength 来代替 1000 * 1000(会导致内容不完整) .但是contentLength 返回 -1 。会导致奔溃。
ResponseBody responseBody = response.peekBody(1000 * 1000);
String bodyInfo = responseBody.string();
Log.e(TAG,"isSuccess: "+successful + "contentLength : "+contentLength);
Log.e(TAG," consume time : "+(responseTime-requestTime));
Log.e(TAG,"responseUrl: "+responseUrl);
Log.e(TAG,"response info : "+bodyInfo);
return chain.proceed(chain.request());
}
}
注意: 但我们想打印服务器返回的数据时,不要直接使用 response.body().string();这可能会导致流数据的关闭,导致后续的回调中处理数据而报错。如何处理,我在代码中也有说明。
至于拦截器的使用,其实和上面的也一样:
if (BuildConfig.DEBUG) {
builder.addInterceptor(new LoggingInterceptor());
}
- header的处理(暂未使用)。 添加使用方式和上面一样
private class HeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
/*
在内部我们可以对请求头做一些处理 比如拼接等等的
*/
Log.e(TAG," HeaderInterceptor intercept ");
return chain.proceed(chain.request());
}
}
- 缓存 CacheInterceptor 。 同样,下面是代码
private final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = chain -> {
Request request = chain.request();
if(!NetUtil.isNetWorkGood(mContext)){
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
Log.e(TAG,"no network");
}
Response originalResponse = chain.proceed(request);
if(NetUtil.isNetWorkGood(mContext)){
//有网的时候读接口上的@Headers里的配置,你可以在这里进行统一的设置
String cacheControl = request.cacheControl().toString();
return originalResponse.newBuilder()
.header("Cache-Control", cacheControl)
.removeHeader("Pragma")
.build();
}else{
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=2419200")
.removeHeader("Pragma")
.build();
}
};
OkHttpClient.Builder builder = new OkHttpClient()
.newBuilder()
.connectTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS)
.readTimeout(READ_TIME_OUT, TimeUnit.SECONDS)
.addInterceptor(new HeaderInterceptor())
.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
;
当然 拦截器的用处远不止如此,比如Struts2
的拦截器就有 20 多个 之多 , 可以做权限校验等等…
我们可以根据自己不同的需求让它为我们做不同的事情。