一、前言
此前编译过一篇博文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控制刷新的时间和机制。