1. 程式人生 > >OkHttp快取max-age詳解補充

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控制重新整理的時間和機制。