OkHttp缓存max-age详解补充

一、前言

此前编译过一篇博文OKHTTP缓存max-age和max-stale详解,在里面提到过一个问题,就是max-age在request和response中设置效果是否一样,下面将会从实验测试的角度来对这个参数进行说明。

二、测试验证和说明

2.1 实验测试代码说明
OKHttp的构建部分

 OkHttpClient.Builder builder = new OkHttpClient.Builder();
 builder.cache(new Cache(context.getCacheDir(),
                            CONST_10 * CONST_1024 * CONST_1024)); //设置缓存
 builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 builder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 builder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 Interceptor interceptor = new NetCacheInterceptor(); //定义response中的max-age缓存信息
 builder.addInterceptor(new LocalCacheInterceptor()); //设置request中的max-age缓存信息
 builder.addNetworkInterceptor(interceptor);
 builder.addInterceptor(new LoggingInterceptor());
 factory = builder.build();

NetCacheInterceptor设置Response中的max-age

public class NetCacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        CacheControl cacheControl = new CacheControl.Builder()
                        .maxAge(300, TimeUnit.SECONDS).build();
        Response response = chain.proceed(request);
       return response.newBuilder()
                .removeHeader("Pragma")
               .removeHeader("Cache-Control")
               .header("Cache-Control", cacheControl.toString())
                .build();
    }
}

LocalCacheInterceptor设置Request中的max-age信息

public class LocalCacheInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        CacheControl cacheControl = new CacheControl.Builder().maxAge(60, TimeUnit.SECONDS).build();
        request = request.newBuilder()
                .cacheControl(cacheControl)
                .build();
        return chain.proceed(request);
    }
}

网络请求的代码

//每隔3秒进行一次网络请求
  Observable.interval(3, TimeUnit.SECONDS).subscribe(
                    new Action1<Long>() {
                        @Override
                        public void call(Long aLong) {
                            RetrofitResearch.getInstance(this)
                .getTopRecommendList()
                .subscribeOn(Schedulers.computation())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<ComicBeanNoCountResult>() {
                               @Override
                               public void call(ComicBeanNoCountResult comicBeanNoCountResult) {
                                   Log.d("yansm", "message =" + comicBeanNoCountResult.message);
                               }
                           },

                        new Action1<Throwable>() {
                            @Override
                            public void call(Throwable throwable) {
                                Log.d("yansm",  throwable.getMessage());
                            }
                        });
    }
                        }
                    }
            );

2.2 实验测试
2.2.1 仅在request中设置max-age
在OKHttp的构建部分中注释掉设置Response部分的代码,参考如下:

 OkHttpClient.Builder builder = new OkHttpClient.Builder();
 builder.cache(new Cache(context.getCacheDir(),
                            CONST_10 * CONST_1024 * CONST_1024)); //设置缓存
 builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 builder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 builder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 Interceptor interceptor = new NetCacheInterceptor(); //定义response中的max-age缓存信息
 builder.addInterceptor(new LocalCacheInterceptor()); //设置request中的max-age缓存信息
// builder.addNetworkInterceptor(interceptor);
 builder.addInterceptor(new LoggingInterceptor());
 factory = builder.build();

测试结果
通过抓包可以看出,每隔3秒APP依旧会发送一次网络请求
这里写图片描述
但是在Request设置的代码中定义的是60秒(参见上述代码中的设置),在APP私有目录下查看是否有缓存文件生成,结果cache目录下并没有缓存文件生成
这里写图片描述
结论:如果单单只在Request请求中设置max-age时间,max-age时间是没有生效的,并且没有生成缓存文件。
2.2.2 仅在Response中设置缓存时间max-age
在OKHttp的构建部分中注释掉设置Request部分的代码,参考如下:

 OkHttpClient.Builder builder = new OkHttpClient.Builder();
 builder.cache(new Cache(context.getCacheDir(),
                            CONST_10 * CONST_1024 * CONST_1024)); //设置缓存
 builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 builder.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 builder.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
 Interceptor interceptor = new NetCacheInterceptor(); //定义response中的max-age缓存信息
// builder.addInterceptor(new LocalCacheInterceptor()); //设置request中的max-age缓存信息
 builder.addNetworkInterceptor(interceptor);
 builder.addInterceptor(new LoggingInterceptor());
 factory = builder.build();

另外为了方便测试,将NetCacheInterceptor.java中的时间值设置为60s。
测试结果
抓包发现,APP每隔60s才会发送一次网络请求。
这里写图片描述

在APP的私有目录下查看是否有缓存文件的生成,结果发现cache目录下生成了缓存文件。
这里写图片描述
在APP的运行日志中可以查看到,每隔3秒APP是会主动请求一次的,由于存在缓存的原因,因此最终只在每隔60s之后才会发送一个网络请求。
这里写图片描述
结论:在Response中设置网络的cache时间符合我们预期的结果,在存在缓存和缓存没有过期的情况下,网络请求直接从缓存中读取数据,在缓存过期的情况下才向后台服务器直接发送网络请求,请求成功之后再生成新的缓存。
2.2.3 同时设置Request和Response中的cache时间值
将OKHttp的构建部分中的代码还原成同时设置Request和Response的情况,只是Request的时间间隔设置成60s,Response的时间设置成300s,对APP的网络请求进行测试,测试结果如下:

图中出现403的情况是在21:02:14之后将lbs.sougu.net.cn设置为黑名单,原因见下面分析。
日志中的网络请求如下:
这里写图片描述

从日志中可以看出,每隔3秒APP也会发送网络请求,但是由于存在缓存的原因,并不会每隔3秒就直接向服务端发送网络请求。而是根据Request中设定的时间,在每隔60s之后,才向服务器发送网络请求。根据实验二中的情况,如果没有设置Request的时间值,APP直接向服务端发送网络请求的时间应该在300s之后。另外在测试120s之后,也就是APP直接向服务器发送两次请求之后,将测试的url(lbs.sougu.net.cn)在抓包工具上设置成黑名单,结果发现APP在180s进行第三次请求报错之后,APP会定时向网络直接每隔3s请求一次。

三、实验结论

以下是本次实验的总结:
1、在Response中设置max-age的时间信息,可以在APP端生成缓存文件,在缓存不过期的情况下,APP不会直接向服务器请求数据,在缓存过期的情况下,APP客户端会向服务器直接请求生成新的缓存。
2、如果是仅仅设置Request中的max-age时间,是不会生成缓存文件,并且没有缓存是否过期的情况,都是直接向后台服务器直接请求数据。
3、如果同时设置了Response和Request中的max-age 缓存时间,如果Request中的max-age时间小于Response中的max-age时间,APP会根据Request中max-age时间周期去直接进行网络请求,如果碰到断网或者网络请求不通的情况,即使缓存还在有效期内(Response中设置的max-age时间足够大),在Request设置的max-age过期之后,APP也会直接去进行网络请求。
因此可以考虑在APP的设计中一个和好的网络缓存场景,用Response的max-age控制缓存的时间,用Request中max-age控制刷新的时间和机制。

扫描二维码关注公众号,回复: 3943643 查看本文章

猜你喜欢

转载自blog.csdn.net/polo2044/article/details/82228886