1. 程式人生 > >OKHTTP之快取配置詳解

OKHTTP之快取配置詳解

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出

前言

在Android開發中我們經常要進行各種網路訪問,比如檢視各類新聞、檢視各種圖片。但有一種情形就是我們每次重複傳送的網路請求其實返回的內容都是一樣的。比如一個電影類APP,每一次向伺服器申請某個電影的相關資訊,如封面、簡介、演員表等等,它們的資訊都是一樣的。顯然,這樣有點浪費資源,最主要的是這些重複的請求產生了沒有必要的流量。流量、流量、流量!!!重要的事情說三遍!剛開始工作的我也不懂,後來才發現,流量是要付費的,而且超貴,公司那麼小,一個月要支付寬頻運營商鉅額的流量費用。所以領導們都想方設法地要節省頻寬。
其實這在整個軟體開發中隨時可見,解決的方法就是把重複請求的資料快取在本地,並設定超時時間,在規定時間內,客戶端不再向遠端請求資料,而是直接從本地快取中取資料。這樣一來提高了響應速度,二來節省了網路頻寬(也就是節省了錢)。
本文就是講解在OKHTTP中如何配置快取。

HTTP協議中快取相關

為了更好的講解OKHTTP怎麼設定快取,我們追根溯源先從瀏覽器的快取說起,這樣後面的OKHTTP快取內容自然更加好理解。

我這部分內容也是經網路上查閱,這一篇寫得很詳細瀏覽器 HTTP 協議快取機制詳解。以下內容基本出自於此文章。

快取分類

http請求有服務端和客戶端之分。因此快取也可以分為兩個型別服務端側和客戶端側。

服務端側快取

常見的服務端有Ngix和Apache。服務端快取又分為代理伺服器快取和反向代理伺服器快取。常見的CDN就是伺服器快取。這個好理解,當瀏覽器重複訪問一張圖片地址時,CDN會判斷這個請求有沒有快取,如果有的話就直接返回這個快取的請求回覆,而不再需要讓請求到達真正的服務地址,這麼做的目的是減輕服務端的運算壓力。

客戶端側快取

客戶端主要指瀏覽器(如IE、Chrome等),當然包括我們的OKHTTPClient.客戶端第一次請求網路時,伺服器返回回覆資訊。如果資料正常的話,客戶端快取在本地的快取目錄。當客戶端再次訪問同一個地址時,客戶端會檢測本地有沒有快取,如果有快取的話,資料是有沒有過期,如果沒有過期的話則直接運用快取內容。

而我們講的就是客戶端的快取。

快取中重要的概念

Cache-Control

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

這裡寫圖片描述
然後,檢視服務端返回來的資訊如下:

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是由伺服器返回的Response中新增的頭資訊,它的目的是告訴客戶端是要從本地讀取快取還是直接從伺服器摘取訊息。它有不同的值,每一個值有不同的作用。

  • max-age:這個引數告訴瀏覽器將頁面快取多長時間,超過這個時間後才再次向伺服器發起請求檢查頁面是否有更新。對於靜態的頁面,比如圖片、CSS、Javascript,一般都不大變更,因此通常我們將儲存這些內容的時間設定為較長的時間,這樣瀏覽器會不會向瀏覽器反覆發起請求,也不會去檢查是否更新了。
  • s-maxage:這個引數告訴快取伺服器(proxy,如Squid)的快取頁面的時間。如果不單獨指定,快取伺服器將使用max-age。對於動態內容(比如文件的檢視頁面),我們可告訴瀏覽器很快就過時了(max-age=0),並告訴快取伺服器(Squid)保留內容一段時間(比如,s-maxage=7200)。一旦我們更新文件,我們將告訴Squid清除老的快取版本。
  • must-revalidate:這告訴瀏覽器,一旦快取的內容過期,一定要向伺服器詢問是否有新版本。
  • proxy-revalidate:proxy上的快取一旦過期,一定要向伺服器詢問是否有新版本。
  • no-cache:不做快取。
  • no-store:資料不在硬碟中臨時儲存,這對需要保密的內容比較重要。
  • public:告訴快取伺服器, 即便是對於不該快取的內容也快取起來,比如當用戶已經認證的時候。所有的靜態內容(圖片、Javascript、CSS等)應該是public的。
  • private:告訴proxy不要快取,但是瀏覽器可使用private cache進行快取。一般登入後的個性化頁面是private的。
  • no-transform: 告訴proxy不進行轉換,比如告訴手機瀏覽器不要下載某些圖片。
  • max-stale指示客戶機可以接收超出超時期間的響應訊息。如果指定max-stale訊息的值,那麼客戶機可以接收超出超時期指定值之內的響應訊息。

我們上面的例子是Cache-Control:private。說明伺服器希望客戶端不要快取訊息,但是可以進行private cache方法進行快取。這是因為http://blog.csdn.net/briblue是我的部落格頁面,與使用者系統相關,所以為了安全起見,建議用private cache的方式快取。

在OKHttp開發中我們常見到的有下面幾個:
* max-age
* no-cache
* max-stale

expires

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

Last-Modified/If-Modified-Since

這個需要配合Cache-Control使用

Last-Modified:標示這個響應資源的最後修改時間。web伺服器在響應請求時,告訴瀏覽器資源的最後修改時間。

If-Modified-Since:當資源過期時(使用Cache-Control標識的max-age),發現資源具有Last-Modified宣告,則再次向web伺服器請求時帶上頭 If-Modified-Since,表示請求時間。web伺服器收到請求後發現有頭If-Modified-Since 則與被請求資源的最後修改時間進行比對。若最後修改時間較新,說明資源又被改動過,則響應整片資源內容(寫在響應訊息包體內),HTTP 200;若最後修改時間較舊,說明資源無新修改,則響應HTTP 304 (無需包體,節省瀏覽),告知瀏覽器繼續使用所儲存的cache。

Etag/If-None-Match

這個也需要配合Cache-Control使用

Etag對應請求的資源在伺服器中的唯一標識(具體規則由伺服器決定),比如一張圖片,它在伺服器中的標識為ETag: W/”ACXbWXd1n0CGMtAd65PcoA==”。

If-None-Match 如果瀏覽器在Cache-Control:max-age=60設定的時間超時後,發現訊息頭中還設定了Etag值。然後,瀏覽器會再次向伺服器請求資料並新增In-None-Match訊息頭,它的值就是之前Etag值。伺服器通過Etag來定位資原始檔,根據它是否更新的情況給瀏覽器返回200或者是304。

Etag機制比Last-Modified精確度更高,如果兩者同時設定的話,Etag優先順序更高。

Pragma

Pragma頭域用來包含實現特定的指令,最常用的是Pragma:no-cache。

在HTTP/1.1協議中,它的含義和Cache- Control:no-cache相同。

以上是Http中關於快取的相關資訊。接下來我們進入主題,如何配置OkHttp的快取。

OKHTTP之Cache

OKHTTP如果要設定快取,首要的條件就是設定一個快取資料夾,在Android中為了安全起見,一般設定為私密資料空間。通過getExternalCacheDir()獲取。如然後通過呼叫OKHttpClient.Builder中的cache()方法。如下面程式碼所示:

//快取資料夾
File cacheFile = new File(getExternalCacheDir().toString(),"cache");
//快取大小為10M
int cacheSize = 10 * 1024 * 1024;
//建立快取物件
Cache cache = new Cache(cacheFile,cacheSize);

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

設定好Cache我們就可以正常訪問了。我們可以通過獲取到的Response物件拿到它正常的訊息和快取的訊息。

Response的訊息有兩種型別,CacheResponse和NetworkResponse。CacheResponse代表從快取取到的訊息,NetworkResponse代表直接從服務端返回的訊息。示例程式碼如下:

private void testCache(){
        //快取資料夾
        File cacheFile = new File(getExternalCacheDir().toString(),"cache");
        //快取大小為10M
        int cacheSize = 10 * 1024 * 1024;
        //建立快取物件
        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 {
                    //第一次網路請求
                    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 {
                    //第二次網路請求
                    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地址分別進行了兩次網路訪問,然後分別用Log列印它們的資訊。

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

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

                                                       :@@@.
                                                     [email protected]@@@@@@:   [email protected]@       `@@      @@`   @@     @@
                                                    [email protected]@@@'@@@@:  [email protected]@       `@@      @@`   @@     @@
                                                    @@@     @@@  [email protected]@       `@@      @@`   @@     @@
                                                   [email protected]@       @@: [email protected]@   @@@ `@@      @@` @@@@@@ @@@@@@  @@;@@@@@
                                                   @@@       @@@ [email protected]@  @@@  `@@      @@` @@@@@@ @@@@@@  @@@@@@@@@
                                                   @@@       @@@ [email protected]@ @@@   `@@@@@@@@@@`   @@     @@    @@@   :@@
                                                   @@@       @@@ [email protected]@@@@    `@@@@@@@@@@`   @@     @@    @@#    @@+
                                                   @@@       @@@ [email protected]@@@@+   `@@      @@`   @@     @@    @@:    @@#
                                                    @@:     [email protected]@` [email protected]@@[email protected]@   `@@      @@`   @@     @@    @@#    @@+
                                                    @@@.   [email protected]@@  [email protected]@  @@@  `@@      @@`   @@     @@    @@@   ,@@
                                                     @@@@@@@@@   [email protected]@   @@@ `@@      @@`   @@@@   @@@@  @@@@#@@@@
                                                      @@@@@@@    [email protected]@   #@@ `@@      @@`   @@@@:  @@@@: @@'@@@@@
                                                                                                       @@:
                                                                                                       @@:
                                                                                                       @@:
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.  //
                                                                             [email protected]@@@@@@@@.
                                                                           :@@@@@@@@@@@@@:
                                                                          :@@. '@@@@@' [email protected]@:
                                                                          @@@@@@@@@@@@@@@@@
                                                                          @@@@@@@@@@@@@@@@@

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

                                                       :@@@.
                                                     [email protected]@@@@@@:   [email protected]@       `@@      @@`   @@     @@
                                                    [email protected]@@@'@@@@:  [email protected]@       `@@      @@`   @@     @@
                                                    @@@     @@@  [email protected]@       `@@      @@`   @@     @@
                                                   [email protected]@       @@: [email protected]@   @@@ `@@      @@` @@@@@@ @@@@@@  @@;@@@@@
                                                   @@@       @@@ [email protected]@  @@@  `@@      @@` @@@@@@ @@@@@@  @@@@@@@@@
                                                   @@@       @@@ [email protected]@ @@@   `@@@@@@@@@@`   @@     @@    @@@   :@@
                                                   @@@       @@@ [email protected]@@@@    `@@@@@@@@@@`   @@     @@    @@#    @@+
                                                   @@@       @@@ [email protected]@@@@+   `@@      @@`   @@     @@    @@:    @@#
                                                    @@:     [email protected]@` [email protected]@@[email protected]@   `@@      @@`   @@     @@    @@#    @@+
                                                    @@@.   [email protected]@@  [email protected]@  @@@  `@@      @@`   @@     @@    @@@   ,@@
                                                     @@@@@@@@@   [email protected]@   @@@ `@@      @@`   @@@@   @@@@  @@@@#@@@@
                                                      @@@@@@@    [email protected]@   #@@ `@@      @@`   @@@@:  @@@@: @@'@@@@@
                                                                                                       @@:
                                                                                                       @@:
                                                                                                       @@:
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

列印的結果非常有意思是一個機器人和一個Okhttp的字串。列印的結果主要說明了一個現象,第一次訪問的時候,Response的訊息是NetworkResponse訊息,此時CacheResponse的值為Null.而第二次訪問的時候Response是CahceResponse,而此時NetworkResponse為空。也就說明了上面的示例程式碼能夠進行網路請求的快取。

那麼OKHTTP中的快取就這麼點內容嗎?到此為至嗎?顯然不是。本篇文章開頭講了大段的Http協議中的相關知識點,貌似它們還沒有出現。

其實控制快取的訊息頭往往是服務端返回的資訊中新增的如”Cache-Control:max-age=60”。所以,會有兩種情況。
1. 客戶端和服務端開發能夠很好溝通,按照達成一致的協議,服務端按照規定新增快取相關的訊息頭。
2. 客戶端與服務端的開發根本就不是同一家公司,沒有辦法也不可能要求服務端按照客戶端的意願進行開發。

第一種辦法當然很好,只要伺服器在返回訊息的時候新增好Cache-Control相關的訊息便好。

第二種情況,就很麻煩,你真的無法左右別人的行為。怎麼辦呢?好在OKHTTP能夠很輕易地處理這種情況。那就是定義一個攔截器,人為地新增Response中的訊息頭,然後再傳遞給使用者,這樣使用者拿到的Response就有了我們理想當中的訊息頭Headers,從而達到控制快取的意圖,正所謂移花接木。

快取之攔截器

因為攔截器可以拿到Request和Response,所以可以輕而易舉地加工這些東西。在這裡我們人為地新增Cache-Control訊息頭。

class CacheInterceptor implements Interceptor{

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

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

            //設定快取時間為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;
        //建立快取物件
        final Cache cache = new Cache(cacheFile,cacheSize);

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

程式碼後面部分有省略。主要通過在OkHttpClient.Builder()中addNetworkInterceptor()中新增。而這樣也挺簡單的,就幾步完成了快取程式碼。

攔截器進行快取的缺點

網上有人說用攔截器進行快取是野路子,是HOOK行為。這個我不大同意,前面我有分析過情況,如果客戶端能夠同服務端一起協商開發,當然以伺服器控制的快取訊息頭為準,但問題在於你沒法這樣做。所以,能夠解決問題才是最實在的。

好了,回到正題。用攔截器控制快取有什麼不好的地方呢?我們先看看下面的情況。
1. 網路訪問請求的資源是文字資訊,如新聞列表,這類資訊經常變動,一天更新好幾次,它們用的快取時間應該就很短。
2. 網路訪問請求的資源是圖片或者視訊,它們變動很少,或者是長期不變動,那麼它們用的快取時間就應該很長。

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

okhttp官方文件建議快取方法

okhttp中建議用CacheControl這個類來進行快取策略的制定。
它內部有兩個很重要的靜態例項。

/**強制使用網路請求*/
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常量用來強制使用網路請求。FORCE_CACHE只取本地的快取。它們本身都是CacheControl物件,由內部的Buidler物件構造。下面我們來看看CacheControl.Builder

CacheControl.Builder

它有如下方法:

- noCache();//不使用快取,用網路請求
- noStore();//不使用快取,也不儲存快取
- onlyIfCached();//只使用快取
- noTransform();//禁止轉碼
- maxAge(10, TimeUnit.MILLISECONDS);//設定超時時間為10ms。
- maxStale(10, TimeUnit.SECONDS);//超時之外的超時時間為10s
- minFresh(10, TimeUnit.SECONDS);//超時時間為當前時間加上10秒鐘。

知道了CacheControl的相關資訊,那麼它怎麼使用呢?不同於攔截器設定快取,CacheControl是針對Request的,所以它可以針對每個請求設定不同的快取策略。比如圖片和新聞列表。下面程式碼展示如何用CacheControl設定一個60秒的超時時間。

private void testCacheControl(){
        //快取資料夾
        File cacheFile = new File(getExternalCacheDir().toString(),"cache");
        //快取大小為10M
        int cacheSize = 10 * 1024 * 1024;
        //建立快取物件
        final Cache cache = new Cache(cacheFile,cacheSize);

        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient client = new OkHttpClient.Builder()
                        .cache(cache)
                        .build();
                //設定快取時間為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();

它內部其實就是呼叫onlyIfCached()和maxStale方法。
它的使用方法為

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

但是如前面後提到的,如果快取不符合條件會返回504.這個時候我們要根據情況再進行編碼,如快取不行就再進行一次網路請求。

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

不使用快取

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

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

它的內部其實是呼叫noCache()方法,也就是不快取的意思。
它的使用方法為

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

還有一種情況將maxAge設定為0,也不會取快取,直接走網路。

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

總結

本文其實內容不多,前面講了很多http協議下的快取機制,我認為是值得的,知道了Cache-Control這些定義,才能更好的懂得OKHTTP中的快取設定。能夠明白為什麼它要這樣做,為什麼它可以這樣做。
最後歸納下要點

  • http協議下Cache-Control等訊息頭的作用
  • okhttp如何用攔截器新增Cache-Control訊息頭進行快取定製
  • okhttp如何用CacheControl進行快取的控制。

Ref

相關推薦

OKHTTP快取配置

本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家釋出 前言 在Android開發中我們經常要進行各種網路訪問,比如檢視各類新聞、檢視各種圖片。但有一種情形就是我們每次重複傳送的網路請求其實返回的內容都是一樣的。比如一個電影類APP,每一次向

NginxLocation配置(Location匹配順序)

location有”定位”的意思, 主要是根據Uri來進行不同的定位.在虛擬主機的配置中,是必不可少的. location可以把網站的不同部分,定位到不同的處理方式上. 1.location的基礎語

Redis 持久化 AOF 配置

############################## APPEND ONLY MODE ############################### # By default Redis asynchronously dumps the datase

Qt pro 配置

簡述 使用Qt的時候,我們經常會對pro進行一系列繁瑣的配置,為方便大家理解、查詢,現將常用的配置進行整理。 | 配置 註釋 以“#”開始,到這一行結束。 快捷鍵:Ctrl + / CONFIG 指定編譯器選項和專案配置,值由qmake

Tomcat工作原理檔案配置

一、Tomcat目錄|---bin:存放啟動和關閉tomcat指令碼;|---conf:存放不同的配置檔案(server.xml和web.xml);|---doc:存放Tomcat文件;|---lib/japser/common:存放Tomcat執行需要的庫檔案(JARS);

spring——c3p0配置

<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/200

Web.xml配置context-param

ltr 完成 數據庫 數據 鍵值對 art str htm 方法 轉自:http://blog.csdn.net/liaoxiaohua1981/article/details/6759206 格式定義: [html] view plaincopy

mongo 3.4分片集群系列六:配置數據庫

初始化 kpi 更新 並且 color tag 成員 gin sha 這個系列大致想跟大家分享以下篇章(我會持續更新的↖(^ω^)↗): 1、mongo 3.4分片集群系列之一:淺談分片集群 2、mongo 3.4分片集群系列之二:搭建分片集群--哈希分片 3、mongo

SpringMVC 框架系列組件概述與配置

align 概述 handle ont htm 配置文件 掃描器 springmvc 解析 在上一篇文章 SpringMVC 框架系列之初識與入門實例 的實例中,我們已經知道,SpringMVC 框架是一個 web 層的框架,本篇文章就詳細解釋一下 SpringMVC 框架

Nginx得Location配置精準匹配

location的匹配過程一、location 的定義 location 有“定位”的意思,根據Uri來進行不同的定位。 在虛擬主機的配置中,是必不可少得,location可以把網站的不同部分,定位到不同的處理方式上。二、location 的語法 location [

Mysqlmy.cnf配置

線程池 ext 自動刪除 statement arr 網絡 決定 而不是 amp Mysql之my.cnf配置詳解 mysql5.6的版本有400多個變量可以配置,可以通過下列命令獲得mysql> show variables; 配置文件參數如下: #客戶端設置,即

Spring 基礎教程四:JavaBean基本配置

一:xml 裝配JavaBean屬性含義: 1.id:指定該Bean 的唯一標識。 2.class:指定該Bean 的全限定名。 3.name:為該Bean 指定一到多個別名。多個別名可以用“,”和“;”分割。

Android快取機制硬碟快取DiskLruCache

簡介 防止多圖OOM的核心解決思路就是使用LruCache技術。但LruCache只是管理了記憶體中圖片的儲存與釋放,如果圖片從記憶體中被移除的話,那麼又需要從網路上重新載入一次圖片,這顯然非常耗時。對此,Google又提供了一套硬碟快取的解決方案:DiskLruCache(非Google官方編

Spring-boot入門配置

1.配置檔案 spring-boot預設有兩種配置檔案 appliation.properties appliation.yml 配置檔案預設放在src/main/resources目錄或者是類路徑/config下 配置檔案的作用:修改sprin

spring boot配置

spring boot支援的配置檔案 spring boot支援兩種型別的配置檔案,一種是傳統的預設配置檔案application.properties ,還有一種是現在被廣泛推薦使用的YAML檔案。書寫上properties是採用鍵值對的形式來表示,而YAML是以類似大綱的縮排形式,這

OkHttp原始碼Okio原始碼

請在電腦上閱讀,效果更佳 本文將從兩個技術點講解OkHttp 1. 講解Okio,因為Okhttp的IO操作都是基於Okio,拋開Okio的OkHttp講解是不完美的 2. 講解OkHttp原始碼 Okio 1. Okio簡介 引用官方的一段介紹 Okio是一個補

webpack4配置慢嚼細嚥

前言   經常會有群友問起webpack、react、redux、甚至create-react-app配置等等方面的問題,有些是我也不懂的,慢慢從大家的相互交流中,也學到了不少。 ​  今天就嘗試著一起來聊聊Webpack吧,旨在幫大家加深理解、新手更容易上路,都能從0到1搭建配置自定屬於自己的腳手架,或

Java程式設計師從笨鳥到菜鳥(七十二)細談Spring(四)利用註解實現spring基本配置

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Struts學習Message Resources配置

目錄 一、概述 二、用法 三、建立資源包 四、配置 五、資原始檔放在哪裡 六、Tags 七、Actions 八、國際化 九、JSTL 十、結論 一、概述        Message Resources訊息

webpack4配置新手上路初探

前言   經常會有群友問起webpack、react、redux、甚至create-react-app配置等等方面的問題,有些是我也不懂的,慢慢從大家的相互交流中,也學到了不少。 ​  今天就嘗試著一起來聊聊Webpack吧,旨在幫大家加深理解、新手更容易上路,都能從0到1搭建配置自定屬於自己的腳手架