OKHTTP之緩存配置詳解

前言

在Android開發(fā)中我們經(jīng)常要進行各種網(wǎng)絡(luò)訪問,比如查看各類新聞、查看各種圖片。但有一種情形就是我們每次重復(fù)發(fā)送的網(wǎng)絡(luò)請求其實返回的內(nèi)容都是一樣的。比如一個電影類APP,每一次向服務(wù)器申請某個電影的相關(guān)信息,如封面、簡介、演員表等等,它們的信息都是一樣的。顯然,這樣有點浪費資源,最主要的是這些重復(fù)的請求產(chǎn)生了沒有必要的流量。流量、流量、流量!!!重要的事情說三遍!剛開始工作的我也不懂,后來才發(fā)現(xiàn),流量是要付費的,而且超貴,公司那么小,一個月要支付寬帶運營商巨額的流量費用。所以領(lǐng)導(dǎo)們都想方設(shè)法地要節(jié)省帶寬。

其實這在整個軟件開發(fā)中隨時可見,解決的方法就是把重復(fù)請求的數(shù)據(jù)緩存在本地,并設(shè)置超時時間,在規(guī)定時間內(nèi),客戶端不再向遠程請求數(shù)據(jù),而是直接從本地緩存中取數(shù)據(jù)。這樣一來提高了響應(yīng)速度,二來節(jié)省了網(wǎng)絡(luò)帶寬(也就是節(jié)省了錢)。 本文就是講解在OKHTTP中如何配置緩存。

HTTP協(xié)議中緩存相關(guān)

為了更好的講解OKHTTP怎么設(shè)置緩存,我們追根溯源先從瀏覽器的緩存說起,這樣后面的OKHTTP緩存內(nèi)容自然更加好理解。
我這部分內(nèi)容也是經(jīng)網(wǎng)絡(luò)上查閱,這一篇寫得很詳細瀏覽器 HTTP 協(xié)議緩存機制詳解。以下內(nèi)容基本出自于此文章。

緩存分類

http請求有服務(wù)端和客戶端之分。因此緩存也可以分為兩個類型服務(wù)端側(cè)和客戶端側(cè)。

服務(wù)端側(cè)緩存

常見的服務(wù)端有Ngix和Apache。服務(wù)端緩存又分為代理服務(wù)器緩存和反向代理服務(wù)器緩存。常見的CDN就是服務(wù)器緩存。這個好理解,當(dāng)瀏覽器重復(fù)訪問一張圖片地址時,CDN會判斷這個請求有沒有緩存,如果有的話就直接返回這個緩存的請求回復(fù),而不再需要讓請求到達真正的服務(wù)地址,這么做的目的是減輕服務(wù)端的運算壓力。

客戶端側(cè)緩存

客戶端主要指瀏覽器(如IE、Chrome等),當(dāng)然包括我們的OKHTTPClient.客戶端第一次請求網(wǎng)絡(luò)時,服務(wù)器返回回復(fù)信息。如果數(shù)據(jù)正常的話,客戶端緩存在本地的緩存目錄。當(dāng)客戶端再次訪問同一個地址時,客戶端會檢測本地有沒有緩存,如果有緩存的話,數(shù)據(jù)是有沒有過期,如果沒有過期的話則直接運用緩存內(nèi)容。
而我們講的就是客戶端的緩存。
緩存中重要的概念

Cache-Control

Cache-Control是什么呢?先別急, 我們先用觀察一個結(jié)果,用Fiddler監(jiān)聽瀏覽器訪問http://blog.csdn.net/briblue。如下圖:

這里寫圖片描述
然后,查看服務(wù)端返回來的信息如下:

HTTP/1.1 200 OK
Server: openresty
Date: Mon, 24 Oct 2016 09:00:34 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
Vary: Accept-Encoding
Cache-Control: private
X-Powered-By: PHP 5.4.28
Content-Encoding: gzip

可以看到頭信息中有這么一行:
Cache-Control: private

Cache-control是由服務(wù)器返回的Response中添加的頭信息,它的目的是告訴客戶端是要從本地讀取緩存還是直接從服務(wù)器摘取消息。它有不同的值,每一個值有不同的作用。

  • max-age:這個參數(shù)告訴瀏覽器將頁面緩存多長時間,超過這個時間后才再次向服務(wù)器發(fā)起請求檢查頁面是否有更新。對于靜態(tài)的頁面,比如圖片、CSS、Javascript,一般都不大變更,因此通常我們將存儲這些內(nèi)容的時間設(shè)置為較長的時間,這樣瀏覽器會不會向瀏覽器反復(fù)發(fā)起請求,也不會去檢查是否更新了。

  • s-maxage:這個參數(shù)告訴緩存服務(wù)器(proxy,如Squid)的緩存頁面的時間。如果不單獨指定,緩存服務(wù)器將使用max-age。對于動態(tài)內(nèi)容(比如文檔的查看頁面),我們可告訴瀏覽器很快就過時了(max-age=0),并告訴緩存服務(wù)器(Squid)保留內(nèi)容一段時間(比如,s-maxage=7200)。一旦我們更新文檔,我們將告訴Squid清除老的緩存版本。

  • must-revalidate:這告訴瀏覽器,一旦緩存的內(nèi)容過期,一定要向服務(wù)器詢問是否有新版本。

  • proxy-revalidate:proxy上的緩存一旦過期,一定要向服務(wù)器詢問是否有新版本。

  • no-cache:不做緩存。

  • no-store:數(shù)據(jù)不在硬盤中臨時保存,這對需要保密的內(nèi)容比較重要。

  • public:告訴緩存服務(wù)器, 即便是對于不該緩存的內(nèi)容也緩存起來,比如當(dāng)用戶已經(jīng)認證的時候。所有的靜態(tài)內(nèi)容(圖片、Javascript、CSS等)應(yīng)該是public的。

  • private:告訴proxy不要緩存,但是瀏覽器可使用private cache進行緩存。一般登錄后的個性化頁面是private的。

  • no-transform: 告訴proxy不進行轉(zhuǎn)換,比如告訴手機瀏覽器不要下載某些圖片。

  • max-stale指示客戶機可以接收超出超時期間的響應(yīng)消息。如果指定max-stale消息的值,那么客戶機可以接收超出超時期指定值之內(nèi)的響應(yīng)消息。

我們上面的例子是Cache-Control:private。說明服務(wù)器希望客戶端不要緩存消息,但是可以進行private cache方法進行緩存。這是因為http://blog.csdn.net/briblue是我的博客頁面,與用戶系統(tǒng)相關(guān),所以為了安全起見,建議用private cache的方式緩存。
在OKHttp開發(fā)中我們常見到的有下面幾個:

  • max-age
  • no-cache
  • max-stale

expires

expires的效果等同于Cache-Control,不過它是Http 1.0的內(nèi)容,它的作用是告訴瀏覽器緩存的過期時間,在此時間內(nèi)瀏覽器不需要直接訪問服務(wù)器地址直接用緩存內(nèi)容就好了。 expires最大的問題在于如果服務(wù)器時間和本地瀏覽器相差過大的問題。那樣誤差就很大。所以基本上用Cache-Control:max-age=多少秒的形式代替。

Last-Modified/If-Modified-Since

這個需要配合Cache-Control使用

  • Last-Modified:標示這個響應(yīng)資源的最后修改時間。web服務(wù)器在響應(yīng)請求時,告訴瀏覽器資源的最后修改時間。
  • If-Modified-Since:當(dāng)資源過期時(使用Cache-Control標識的max-age),發(fā)現(xiàn)資源具有Last-Modified聲明,則再次向web服務(wù)器請求時帶上頭 If-Modified-Since,表示請求時間。web服務(wù)器收到請求后發(fā)現(xiàn)有頭If-Modified-Since 則與被請求資源的最后修改時間進行比對。若最后修改時間較新,說明資源又被改動過,則響應(yīng)整片資源內(nèi)容(寫在響應(yīng)消息包體內(nèi)),HTTP 200;若最后修改時間較舊,說明資源無新修改,則響應(yīng)HTTP 304 (無需包體,節(jié)省瀏覽),告知瀏覽器繼續(xù)使用所保存的cache。

Etag/If-None-Match

這個也需要配合Cache-Control使用
Etag對應(yīng)請求的資源在服務(wù)器中的唯一標識(具體規(guī)則由服務(wù)器決定),比如一張圖片,它在服務(wù)器中的標識為ETag: W/”ACXbWXd1n0CGMtAd65PcoA==”。
If-None-Match 如果瀏覽器在Cache-Control:max-age=60設(shè)置的時間超時后,發(fā)現(xiàn)消息頭中還設(shè)置了Etag值。然后,瀏覽器會再次向服務(wù)器請求數(shù)據(jù)并添加In-None-Match消息頭,它的值就是之前Etag值。服務(wù)器通過Etag來定位資源文件,根據(jù)它是否更新的情況給瀏覽器返回200或者是304。
Etag機制比Last-Modified精確度更高,如果兩者同時設(shè)置的話,Etag優(yōu)先級更高。

Pragma

Pragma頭域用來包含實現(xiàn)特定的指令,最常用的是Pragma:no-cache。
在HTTP/1.1協(xié)議中,它的含義和Cache- Control:no-cache相同。
以上是Http中關(guān)于緩存的相關(guān)信息。接下來我們進入主題,如何配置OkHttp的緩存。

OKHTTP之Cache

OKHTTP如果要設(shè)置緩存,首要的條件就是設(shè)置一個緩存文件夾,在Android中為了安全起見,一般設(shè)置為私密數(shù)據(jù)空間。通過getExternalCacheDir()獲取。如然后通過調(diào)用OKHttpClient.Builder中的cache()方法。如下面代碼所示:

//緩存文件夾
File cacheFile = new File(getExternalCacheDir().toString(),"cache");
//緩存大小為10M
int cacheSize = 10 * 1024 * 1024;
//創(chuàng)建緩存對象
Cache cache = new Cache(cacheFile,cacheSize);

OkHttpClient client = new OkHttpClient.Builder()
        .cache(cache)
        .build();

設(shè)置好Cache我們就可以正常訪問了。我們可以通過獲取到的Response對象拿到它正常的消息和緩存的消息。

Response的消息有兩種類型,CacheResponse和NetworkResponse。CacheResponse代表從緩存取到的消息,NetworkResponse代表直接從服務(wù)端返回的消息。示例代碼如下:

private void testCache(){
        //緩存文件夾
        File cacheFile = new File(getExternalCacheDir().toString(),"cache");
        //緩存大小為10M
        int cacheSize = 10 * 1024 * 1024;
        //創(chuàng)建緩存對象
        final Cache cache = new Cache(cacheFile,cacheSize);

        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient client = new OkHttpClient.Builder()
                        .cache(cache)
                        .build();
                //官方的一個示例的url
                String url = "http://publicobject.com/helloworld.txt";

                Request request = new Request.Builder()
                        .url(url)
                        .build();
                Call call1 = client.newCall(request);
                Response response1 = null;
                try {
                    //第一次網(wǎng)絡(luò)請求
                    response1 = call1.execute();
                    Log.i(TAG, "testCache: response1 :"+response1.body().string());
                    Log.i(TAG, "testCache: response1 cache :"+response1.cacheResponse());
                    Log.i(TAG, "testCache: response1 network :"+response1.networkResponse());
                    response1.body().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                Call call12 = client.newCall(request);

                try {
                    //第二次網(wǎng)絡(luò)請求
                    Response response2 = call12.execute();
                    Log.i(TAG, "testCache: response2 :"+response2.body().string());
                    Log.i(TAG, "testCache: response2 cache :"+response2.cacheResponse());
                    Log.i(TAG, "testCache: response2 network :"+response2.networkResponse());
                    Log.i(TAG, "testCache: response1 equals response2:"+response2.equals(response1));
                    response2.body().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

我們在上面的代碼中,用同一個url地址分別進行了兩次網(wǎng)絡(luò)訪問,然后分別用Log打印它們的信息。

10-24 21:17:04.720 9901-17925/? I/SeniorActivity: testCache: response1 :
                                                                           \\           //
                                                                            \\  .ooo.  //
                                                                             .@@@@@@@@@.
                                                                           :@@@@@@@@@@@@@:
                                                                          :@@. '@@@@@' .@@:
                                                                          @@@@@@@@@@@@@@@@@
                                                                          @@@@@@@@@@@@@@@@@

                                                                     :@@ :@@@@@@@@@@@@@@@@@. @@:
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                          @@@@@@@@@@@@@@@@@
                                                                          '@@@@@@@@@@@@@@@'
                                                                             @@@@   @@@@
                                                                             @@@@   @@@@
                                                                             @@@@   @@@@
                                                                             '@@'   '@@'

                                                       :@@@.
                                                     .@@@@@@@:   +@@       `@@      @@`   @@     @@
                                                    .@@@@'@@@@:  +@@       `@@      @@`   @@     @@
                                                    @@@     @@@  +@@       `@@      @@`   @@     @@
                                                   .@@       @@: +@@   @@@ `@@      @@` @@@@@@ @@@@@@  @@;@@@@@
                                                   @@@       @@@ +@@  @@@  `@@      @@` @@@@@@ @@@@@@  @@@@@@@@@
                                                   @@@       @@@ +@@ @@@   `@@@@@@@@@@`   @@     @@    @@@   :@@
                                                   @@@       @@@ +@@@@@    `@@@@@@@@@@`   @@     @@    @@#    @@+
                                                   @@@       @@@ +@@@@@+   `@@      @@`   @@     @@    @@:    @@#
                                                    @@:     .@@` +@@@+@@   `@@      @@`   @@     @@    @@#    @@+
                                                    @@@.   .@@@  +@@  @@@  `@@      @@`   @@     @@    @@@   ,@@
                                                     @@@@@@@@@   +@@   @@@ `@@      @@`   @@@@   @@@@  @@@@#@@@@
                                                      @@@@@@@    +@@   #@@ `@@      @@`   @@@@:  @@@@: @@'@@@@@
                                                                                                       @@:
                                                                                                       @@:
                                                                                                       @@:
10-24 21:17:04.720 9901-17925/? I/SeniorActivity: testCache: response1 cache :null
10-24 21:17:04.720 9901-17925/? I/SeniorActivity: testCache: response1 network :Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
10-24 21:17:05.031 9901-17925/? I/SeniorActivity: testCache: response2 :
                                                                           \\           //
                                                                            \\  .ooo.  //
                                                                             .@@@@@@@@@.
                                                                           :@@@@@@@@@@@@@:
                                                                          :@@. '@@@@@' .@@:
                                                                          @@@@@@@@@@@@@@@@@
                                                                          @@@@@@@@@@@@@@@@@

                                                                     :@@ :@@@@@@@@@@@@@@@@@. @@:
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                     @@@ '@@@@@@@@@@@@@@@@@, @@@
                                                                          @@@@@@@@@@@@@@@@@
                                                                          '@@@@@@@@@@@@@@@'
                                                                             @@@@   @@@@
                                                                             @@@@   @@@@
                                                                             @@@@   @@@@
                                                                             '@@'   '@@'

                                                       :@@@.
                                                     .@@@@@@@:   +@@       `@@      @@`   @@     @@
                                                    .@@@@'@@@@:  +@@       `@@      @@`   @@     @@
                                                    @@@     @@@  +@@       `@@      @@`   @@     @@
                                                   .@@       @@: +@@   @@@ `@@      @@` @@@@@@ @@@@@@  @@;@@@@@
                                                   @@@       @@@ +@@  @@@  `@@      @@` @@@@@@ @@@@@@  @@@@@@@@@
                                                   @@@       @@@ +@@ @@@   `@@@@@@@@@@`   @@     @@    @@@   :@@
                                                   @@@       @@@ +@@@@@    `@@@@@@@@@@`   @@     @@    @@#    @@+
                                                   @@@       @@@ +@@@@@+   `@@      @@`   @@     @@    @@:    @@#
                                                    @@:     .@@` +@@@+@@   `@@      @@`   @@     @@    @@#    @@+
                                                    @@@.   .@@@  +@@  @@@  `@@      @@`   @@     @@    @@@   ,@@
                                                     @@@@@@@@@   +@@   @@@ `@@      @@`   @@@@   @@@@  @@@@#@@@@
                                                      @@@@@@@    +@@   #@@ `@@      @@`   @@@@:  @@@@: @@'@@@@@
                                                                                                       @@:
                                                                                                       @@:
                                                                                                       @@:
10-24 21:17:05.031 9901-17925/? I/SeniorActivity: testCache: response2 cache :Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
10-24 21:17:05.031 9901-17925/? I/SeniorActivity: testCache: response2 network :null
10-24 21:17:05.031 9901-17925/? I/SeniorActivity: testCache: response1 equals response2:false

打印的結(jié)果非常有意思是一個機器人和一個Okhttp的字符串。打印的結(jié)果主要說明了一個現(xiàn)象,第一次訪問的時候,Response的消息是NetworkResponse消息,此時CacheResponse的值為Null.而第二次訪問的時候Response是CahceResponse,而此時NetworkResponse為空。也就說明了上面的示例代碼能夠進行網(wǎng)絡(luò)請求的緩存。
那么OKHTTP中的緩存就這么點內(nèi)容嗎?到此為至嗎?顯然不是。本篇文章開頭講了大段的Http協(xié)議中的相關(guān)知識點,貌似它們還沒有出現(xiàn)。
其實控制緩存的消息頭往往是服務(wù)端返回的信息中添加的如”Cache-Control:max-age=60”。所以,會有兩種情況。

  1. 客戶端和服務(wù)端開發(fā)能夠很好溝通,按照達成一致的協(xié)議,服務(wù)端按照規(guī)定添加緩存相關(guān)的消息頭。
  2. 客戶端與服務(wù)端的開發(fā)根本就不是同一家公司,沒有辦法也不可能要求服務(wù)端按照客戶端的意愿進行開發(fā)。

第一種辦法當(dāng)然很好,只要服務(wù)器在返回消息的時候添加好Cache-Control相關(guān)的消息便好。
第二種情況,就很麻煩,你真的無法左右別人的行為。怎么辦呢?好在OKHTTP能夠很輕易地處理這種情況。那就是定義一個攔截器,人為地添加Response中的消息頭,然后再傳遞給用戶,這樣用戶拿到的Response就有了我們理想當(dāng)中的消息頭Headers,從而達到控制緩存的意圖,正所謂移花接木。

緩存之?dāng)r截器

因為攔截器可以拿到Request和Response,所以可以輕而易舉地加工這些東西。在這里我們?nèi)藶榈靥砑覥ache-Control消息頭。

class CacheInterceptor implements Interceptor{

        @Override
        public Response intercept(Chain chain) throws IOException {

            Response originResponse = chain.proceed(chain.request());

            //設(shè)置緩存時間為60秒,并移除了pragma消息頭,移除它的原因是因為pragma也是控制緩存的一個消息頭屬性
            return originResponse.newBuilder().removeHeader("pragma")
                    .header("Cache-Control","max-age=60").build();
        }
    }

定義好攔截器中后,我們可以添加到OKHttpClient中了。

private void testCacheInterceptor(){
        //緩存文件夾
        File cacheFile = new File(getExternalCacheDir().toString(),"cache");
        //緩存大小為10M
        int cacheSize = 10 * 1024 * 1024;
        //創(chuàng)建緩存對象
        final Cache cache = new Cache(cacheFile,cacheSize);

        OkHttpClient client = new OkHttpClient.Builder()
                .addNetworkInterceptor(new CacheInterceptor())
                .cache(cache)
                .build();
        .......
}

代碼后面部分有省略。主要通過在OkHttpClient.Builder()中addNetworkInterceptor()中添加。而這樣也挺簡單的,就幾步完成了緩存代碼。

攔截器進行緩存的缺點

網(wǎng)上有人說用攔截器進行緩存是野路子,是HOOK行為。這個我不大同意,前面我有分析過情況,如果客戶端能夠同服務(wù)端一起協(xié)商開發(fā),當(dāng)然以服務(wù)器控制的緩存消息頭為準,但問題在于你沒法這樣做。所以,能夠解決問題才是最實在的。

好了,回到正題。用攔截器控制緩存有什么不好的地方呢?我們先看看下面的情況。

  1. 網(wǎng)絡(luò)訪問請求的資源是文本信息,如新聞列表,這類信息經(jīng)常變動,一天更新好幾次,它們用的緩存時間應(yīng)該就很短。
  2. 網(wǎng)絡(luò)訪問請求的資源是圖片或者視頻,它們變動很少,或者是長期不變動,那么它們用的緩存時間就應(yīng)該很長。

那么,問題來了。 因為OKHTTP開發(fā)建議是同一個APP,用同一個OKHTTPCLIENT對象這是為了只有一個緩存文件訪問入口。這個很容易理解,單例模式嘛。但是問題攔截器是在OKHttpClient.Builder當(dāng)中添加的。如果在攔截器中定義緩存的方法會導(dǎo)致圖片的緩存和新聞列表的緩存時間是一樣的,這顯然是不合理的,這屬于一刀切,就像這兩天專家說的要把年收入12萬元的人群劃分為高收入人群而不區(qū)別北上廣深的房價物價情況。真實的情況不應(yīng)該是圖片請求有它的緩存時間,新聞列表請求有它的緩存時間,應(yīng)該是每一個Request有它的緩存時間。 那么,有解決的方案嗎? 有的,okhttp官方有建議的方法。

okhttp官方文檔建議緩存方法

okhttp中建議用CacheControl這個類來進行緩存策略的制定。 它內(nèi)部有兩個很重要的靜態(tài)實例。

/**強制使用網(wǎng)絡(luò)請求*/
public static final CacheControl FORCE_NETWORK = new Builder().noCache().build();

  /**
   * 強制性使用本地緩存,如果本地緩存不滿足條件,則會返回code為504
   */
  public static final CacheControl FORCE_CACHE = new Builder()
      .onlyIfCached()
      .maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS)
      .build();

我們看到FORCE_NETWORK常量用來強制使用網(wǎng)絡(luò)請求。FORCE_CACHE只取本地的緩存。它們本身都是CacheControl對象,由內(nèi)部的Buidler對象構(gòu)造。下面我們來看看CacheControl.Builder

CacheControl.Builder

它有如下方法:

- noCache();//不使用緩存,用網(wǎng)絡(luò)請求
- noStore();//不使用緩存,也不存儲緩存
- onlyIfCached();//只使用緩存
- noTransform();//禁止轉(zhuǎn)碼
- maxAge(10, TimeUnit.MILLISECONDS);//設(shè)置超時時間為10ms。
- maxStale(10, TimeUnit.SECONDS);//超時之外的超時時間為10s
- minFresh(10, TimeUnit.SECONDS);//超時時間為當(dāng)前時間加上10秒鐘

知道了CacheControl的相關(guān)信息,那么它怎么使用呢?不同于攔截器設(shè)置緩存,CacheControl是針對Request的,所以它可以針對每個請求設(shè)置不同的緩存策略。比如圖片和新聞列表。下面代碼展示如何用CacheControl設(shè)置一個60秒的超時時間。

private void testCacheControl(){
        //緩存文件夾
        File cacheFile = new File(getExternalCacheDir().toString(),"cache");
        //緩存大小為10M
        int cacheSize = 10 * 1024 * 1024;
        //創(chuàng)建緩存對象
        final Cache cache = new Cache(cacheFile,cacheSize);

        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient client = new OkHttpClient.Builder()
                        .cache(cache)
                        .build();
                //設(shè)置緩存時間為60秒
                CacheControl cacheControl = new CacheControl.Builder()
                        .maxAge(60, TimeUnit.SECONDS)
                        .build();
                Request request = new Request.Builder()
                        .url("http://blog.csdn.net/briblue")
                        .cacheControl(cacheControl)
                        .build();

                try {
                    Response response = client.newCall(request).execute();

                    response.body().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }

強制使用緩存

前面有講CacheControl.FORCE_CACHE這個常量。

public static final CacheControl FORCE_CACHE = new Builder()
      .onlyIfCached()
      .maxStale(Integer.MAX_VALUE, TimeUnit.SECONDS)
      .build();

它內(nèi)部其實就是調(diào)用onlyIfCached()和maxStale方法。
它的使用方法為

Request request = new Request.Builder()
            .url("http://blog.csdn.net/briblue")
            .cacheControl(Cache.FORCE_CACHE)
            .build();

但是如前面后提到的,如果緩存不符合條件會返回504.這個時候我們要根據(jù)情況再進行編碼,如緩存不行就再進行一次網(wǎng)絡(luò)請求。

Response forceCacheResponse = client.newCall(request).execute();
     if (forceCacheResponse.code() != 504) {
       // 資源已經(jīng)緩存了,可以直接使用
     } else {
       // 資源沒有緩存,或者是緩存不符合條件了。
     } 

不使用緩存

前面也有講CacheControl.FORCE_NETWORK這個常量。

public static final CacheControl FORCE_NETWORK = new Builder().noCache().build();

它的內(nèi)部其實是調(diào)用noCache()方法,也就是不緩存的意思。
它的使用方法為

Request request = new Request.Builder()
            .url("http://blog.csdn.net/briblue")
            .cacheControl(Cache.FORCE_NETWORK)
            .build();

還有一種情況將maxAge設(shè)置為0,也不會取緩存,直接走網(wǎng)絡(luò)。

Request request = new Request.Builder()
            .url("http://blog.csdn.net/briblue")
            .cacheControl(new CacheControl.Builder()
            .maxAge(0, TimeUnit.SECONDS))
            .build();

總結(jié)

本文其實內(nèi)容不多,前面講了很多http協(xié)議下的緩存機制,我認為是值得的,知道了Cache-Control這些定義,才能更好的懂得OKHTTP中的緩存設(shè)置。能夠明白為什么它要這樣做,為什么它可以這樣做。 最后歸納下要點
http協(xié)議下Cache-Control等消息頭的作用
okhttp如何用攔截器添加Cache-Control消息頭進行緩存定制
okhttp如何用CacheControl進行緩存的控制。

轉(zhuǎn)載至http://blog.csdn.net/briblue/article/details/52920531

Ref

http://www.cnblogs.com/l1pe1/archive/2010/07/14/1777621.html
http://www.cnblogs.com/whoislcj/p/5537640.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,197評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,415評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,104評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,884評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,647評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,130評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,208評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,366評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,887評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,737評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,939評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,478評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,174評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,586評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,827評論 1 283
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,608評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,914評論 2 372

推薦閱讀更多精彩內(nèi)容

  • 本文就是講解在OKHTTP中如何配置緩存。 HTTP協(xié)議中緩存相關(guān) 為了更好的講解OKHTTP怎么設(shè)置緩存,我們追...
    TendaZhang閱讀 3,055評論 7 19
  • 1.OkHttp源碼解析(一):OKHttp初階 2 OkHttp源碼解析(二):OkHttp連接的"前戲"——H...
    隔壁老李頭閱讀 8,358評論 12 43
  • API定義規(guī)范 本規(guī)范設(shè)計基于如下使用場景: 請求頻率不是非常高:如果產(chǎn)品的使用周期內(nèi)請求頻率非常高,建議使用雙通...
    有涯逐無涯閱讀 2,575評論 0 6
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 大家好,之前我們講解了Okhttp網(wǎng)絡(luò)數(shù)據(jù)請求相關(guān)的內(nèi)容,這一節(jié)我們講講數(shù)據(jù)緩存的處理。本節(jié)按以下內(nèi)容講解Okht...
    Ihesong閱讀 10,489評論 6 26