1. 程式人生 > >《HttpClient官方文件》第六章 HTTP 快取

《HttpClient官方文件》第六章 HTTP 快取

原文連結 譯者[xuheyang]

第六章. HTTP快取

6.1. 通用概念

HttpClient Cache 提供了用HttpClient(等效瀏覽器快取的Java實現)來相容HTTP / 1.1的快取層。實現遵循責任鏈模式,HttpClient快取的實現類可以替代預設無快取的HttpClient;完全可以通過快取實現的請求將不會觸發實際的原始請求。在可以的情況下,使用GETs條件If-Modified-Since和/or If-None-Match請求頭,會自動驗證舊的快取項。HTTP / 1.1快取一般被設計成語義透明的,也就是說,快取不會改變客戶端和伺服器端的請求響應之間交換的意義。因此,向一個現有的客戶端-伺服器的關係中新增HttpClient是安全的。儘管從一個HTTP協議的角度來看,快取模組是客戶端的一部分,實現的目標是滿足基於透明快取代理的要求。最後,快取HttpClient包括支援RFC 5861(stale-if-error和stale-while-revalidate)指定的cache – control擴充套件。 當快取HttpClient執行一個請求時,它會通過以下流程:

  • 檢查要求是否符合基本的HTTP 1.1協議並嘗試正確的請求。
  • 重新整理當前請求導致無效的一些快取項。
  • 確定當前請求可以從快取中提供。如果不能, 則直接將這個請求傳送給原始伺服器並換回響應,如果合適的話儲存快取.
  • 如果是cache-servable請求時,將嘗試從快取中讀取。當快取中沒有的情況下,呼叫原始的伺服器,如果可以的話將響應快取。
  • 如果快取中的響應能夠被當做一個響應提供服務,構造一個包含ByteArrayEntity的BasicHttpResponse並返回。否則,嘗試重新驗證對原始伺服器的快取項.
  • 當一個快取的響應不能重新生效的情況下,呼叫原始伺服器,如果可以的話快取響應.

當快取HttpClient收到響應時,它通過以下流程:

  • 根據協議內容,檢查響應。
  • 確定響應是否可以被快取。
  • 如果可以被快取,讀取配置中允許的最多內容,並將其儲存在快取中。
  • 如果對快取來說響應過大,則重新構建被消費的部分響應,並跳過快取流程直接返回。

需要著重注意的是,HttpClient Cache本身並不是一個HttpClient的不同實現,而是通過外掛的方式作為一個額外管道執行請求。

6.2. RFC-2616 規範

我們相信HttpClient快取是無條件地符合RFC-2616。也就是說無論規範表明對於HTTP快取 必須、不必須、可以、不可以,快取層都會試圖以滿足這些條件的方式實現。 這就意味著,當你使用快取模組時,不會發生錯誤的行為。

6.3. Example Usage

下面是一個如何建立一個基本的快取HttpClient例子。根據配置,他會儲存一個最大數量為1000的快取例項,每個最多能夠儲存8192 bytes。這裡的數字僅僅是個例子,並不是規定,也不能被看做成建議。

CacheConfig cacheConfig = CacheConfig.custom()
    .setMaxCacheEntries(1000)
    .setMaxObjectSize(8192)
    .build();
RequestConfig requestConfig = RequestConfig.custom()
    .setConnectTimeout(30000)
    .setSocketTimeout(30000)
    .build();
CloseableHttpClient cachingClient = CachingHttpClients.custom()
    .setCacheConfig(cacheConfig)
    .setDefaultRequestConfig(requestConfig)
    .build();

HttpCacheContext context = HttpCacheContext.create();
HttpGet httpget = new HttpGet("http://www.mydomain.com/content/");
CloseableHttpResponse response = cachingClient.execute(httpget, context);
try {
    CacheResponseStatus responseStatus = context.getCacheResponseStatus();
    switch (responseStatus) {
        case CACHE_HIT:
            System.out.println("A response was generated from the cache with " +
                "no requests sent upstream");
            break;
        case CACHE_MODULE_RESPONSE:
            System.out.println("The response was generated directly by the " +
                "caching module");
            break;
        case CACHE_MISS:
            System.out.println("The response came from an upstream server");
            break;
        case VALIDATED:
            System.out.println("The response was generated from the cache " +
                "after validating the entry with the origin server");
            break;
    }
} finally {
    response.close();
}

6.4. 配置

HttpClient Cache 繼承了所有非快取實現的配置項和引數(包括像超時時間、連線池大小這樣的設定選項)。對於快取的具體配置,可以根據以下幾個方提供一個快取配置例項指定行為:

快取大小,後端儲存支援這些限制,可以像最大的可快取響應體大小一樣指定快取項的數量.

公共/私有快取. 在預設情況下,快取模組本身是一個共享快取,例如,不會快取帶有授權請求頭的響應和標記為”Cache-Control: private”的響應。然而,如果快取僅僅被應用於一個“使用者”(類似於瀏覽器快取的行為)邏輯,那麼它將關閉共享快取設定。

啟發式快取. 按照RFC2616, 快取可以快取特定的快取條目,即使沒有顯示原始設定的快取控制頭。這種行為在預設情況下是關閉的,但是如果你處理的是一個沒有完全設定原始請求頭的請求,你可能想要開啟它。你需要一個可以啟發式的快取,然後指定一個預設的新生命週期,並且/或者資源被最後修改後的一小段時間。參考HTTP/1.1 RFC的13.2.2和13.2.4部分,可以獲得啟發式快取的更多細節。

後臺驗證. 快取模組支援RFC5861的stale-while-revalidate指令,允許後臺特定的快取項重新生效。可以需要調整設定後臺工作執行緒的最小和最大工作數量,以及他們回收前閒置的最大時間。沒有足夠的worker來跟上需求時,您還可以控制佇列的大小用於重新生效執行緒。

6.5. 後端儲存

預設的HttpClient Cache的實現會儲存快取項,並且在應用的JVM記憶體中快取響應體。雖然這些能夠提供高效能,但是有記憶體大小的限制,或者因為快取項在應用重啟後會失效,所以可能並不適用於您的應用。當前版本允許將快取項儲存到硬碟上,或者使用其他外部程序EhCache和Memcached儲存快取項。如果這些選項滿足不了你的應用,可以通過實現HttpCachedStorage提供你自己的後臺儲存,並且在構建的時候提供給快取HttpClient。在這種情況下,快取項會通過你自己的框架儲存,但是會重用所有HTTP/1.1協議的邏輯和快取處理。一般來說,應該能夠建立一個支援原子操作的key/value儲存(類似於java的Map介面)的HttpCachedStorage實現。最後,通過一些額外的努力完全有可能建立一個多層快取層次結構; 比如,包裝一個記憶體中的快取HttpClient在磁碟上的儲存快取條目,在memcached中遠端儲存,後一種模式類似於虛擬記憶體,L1 / L2處理器快取等。