Retrofit开发-拦截器篇

本文介绍了Retrofit结合Okhttp使用拦截器进行日志打印、缓存设置和请求头处理的方法。强调了在日志拦截器中使用HttpLoggingInterceptor.Level.BODY设置日志级别,并提醒在获取服务器返回数据时避免关闭流,以防后续处理错误。还提及了自定义Interceptor的可能性,以及拦截器在权限校验等场景的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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,BASICHEADERSBODY

这样就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 多个 之多 , 可以做权限校验等等…
我们可以根据自己不同的需求让它为我们做不同的事情。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值