2014-12-19 65 views
14

是否有關於如何添加緩存和ETAG/If-None-Match支持Retrofit + OkHttp的正確解釋? 我很努力在2個項目上添加Etag支持,起初我懷疑HTTP頭可能存在問題,另一個項目正確設置了所有內容,並且緩存仍然無法正常工作。改造ETAG和緩存

以下是我嘗試使其工作。結果表明,緩存似乎在應用程序的同一個實例中工作,但只要我重新啓動 - 所有內容都會再次加載。 另外,在我的日誌中,我沒有看到If-None-Match被添加到請求中,所以我假定服務器不知道ETag,並且仍然完全重新計算響應。

這裏有一些代碼示例:

public class RetrofitHttpClient extends UrlConnectionClient 
{ 

    private OkUrlFactory generateDefaultOkUrlFactory() 
    { 
     OkHttpClient client = new com.squareup.okhttp.OkHttpClient(); 

     try 
     { 
      Cache responseCache = new Cache(baseContext.getCacheDir(), SIZE_OF_CACHE); 
      client.setCache(responseCache); 
     } 
     catch (Exception e) 
     { 
      Logger.log(this, e, "Unable to set http cache"); 
     } 

     client.setConnectTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS); 
     client.setReadTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS); 
     return new OkUrlFactory(client); 
    } 

    private final OkUrlFactory factory; 

    public RetrofitHttpClient() 
    { 
     factory = generateDefaultOkUrlFactory(); 
    } 

    @Override 
    protected HttpURLConnection openConnection(retrofit.client.Request request) throws IOException 
    { 
     return factory.open(new URL(request.getUrl())); 
    } 
} 

休息適配器,然後用FULL日誌級別和自定義標記製作:

restAdapter = new RestAdapter.Builder() 
     .setClient(new RetrofitHttpClient()) 
     .setEndpoint(Config.BASE_URL) 
     .setRequestInterceptor(new SignatureSetter()) 
     .setConverter(new JacksonConverter(JsonHelper.getObjectMapper())) 
     .setLogLevel(RestAdapter.LogLevel.FULL) 
     .setLog(new AndroidLog("=NETWORK=")) 
     .build(); 

我有程序的第一個屏幕上的長期要求供測試用。 當我打開應用程序 - 完成請求需要7秒。如果我暫停並恢復應用程序 - 相同的請求需要250毫秒,顯然會觸及緩存。如果我完全關閉應用程序並重新啓動 - 它再次需要7秒鐘。

UPDATE: 至於建議,我已經使用了自定義的改造建設,並附LoggingInterceptor。這是我得到的。

Received response for *** in 449,3ms 
Date: Wed, 07 Jan 2015 09:02:23 GMT 
Server: Apache 
X-Powered-By: PHP/5.4.31 
Access-Control-Allow-Credentials: true 
Pragma: 
Cache-Control: public, max-age=3600 
X-Frame-Options: SAMEORIGIN 
Etag: "hLxLRYztkinJAB453nRV7ncBSuU=-gzip" 
Last-Modified: Wed, 24 Dec 2014 13:09:04 GMT 
Vary: Accept-Encoding 
Content-Encoding: gzip 
Keep-Alive: timeout=2, max=100 
Connection: Keep-Alive 
Transfer-Encoding: chunked 
Content-Type: application/json; charset=UTF-8 
OkHttp-Selected-Protocol: http/1.1 
OkHttp-Sent-Millis: 1420621288104 
OkHttp-Received-Millis: 1420621288554 


Sending request **** on Connection{****:80, [email protected] hostAddress=**** cipherSuite=none protocol=http/1.1} 
Accept: application/json; 
Host: **** 
Connection: Keep-Alive 
Accept-Encoding: gzip 
User-Agent: okhttp/2.2.0 

Response is equal to described above 

如您所見,在下一個請求中不存在If-None-Match標頭。

+0

服務器響應是否正確實施了「Cache-Control」? – 2014-12-28 00:42:42

+0

是的。正如我所提到的,我有2個項目。在1個項目服務器上有Cache-Control:max-age = 0,private,must-revalidate。我知道這看起來不正確。但另一臺服務器具有正確的緩存控制設置,可以在一段時間內進行緩存。 – AAverin 2014-12-28 09:00:24

+0

您是否正在充分消費響應主體?如果你沒有閱讀整個響應主體,它不會被緩存。 (你還需要在最後調用'close()')。 – 2015-01-08 21:55:28

回答

5

我看到這個問題一直得到關注,只要沒有真正的答案,我可以選擇 - 我正在提供我的調查的主題,並關閉現在的線程。

調查和GitHub上改進和okhttp線程的一些討論的最終結果是,OkHttp中有一個問題可能會阻止爲傳出請求設置If-None-Match標記。

這個問題應該在OkHttp 2.3中解決,我在這裏使用'假設',因爲我還沒有測試它是否真的有效。測試很困難,因爲我正在使用Retrofit,而且Retrofit本身必須更新才能使用新版本的OkHttp並添加一些新的Interceptors支持,以便能夠調試由OkHttp設置的所有頭文件。 相關線程在這裏:https://github.com/square/okhttp/issues/831

我不確定是否在此之後更新了Retrofit。希望是的,所以很有可能這個問題已經解決,Etag應該正常工作 - 只要確保你有最新版本的Retrofit和OkHttp。

我會嘗試自己測試一切,一旦我有時間。

+0

現在工作嗎?你測試過了嗎? – amalBit 2016-02-09 08:18:02

0

我有一個類似的問題:即使服務器發送相同的ETAG,OkHttp也沒有達到緩存。

我的問題是SIZE_OF_CACHE。我正在定義一個非常小的尺寸。

試圖增加它(像10名* 1024名* 1024名的作品對我來說) 你也可以探索/數據/數據//文件/高速緩存,看是否真正有存儲有

+0

SIZE_OF_CACHE = 10 * 1024 * 1024 - 這就是我現在所擁有的,並且它仍然無法按預期工作。我可以嘗試增加它,但最有可能不是這個問題 – AAverin 2014-12-30 18:34:14

1

使用OkHttp攔截器的東西將幫助您診斷在您的應用程序中出現在&中的標頭。 interceptors doc給出了一個攔截器的代碼示例,該攔截器在網絡上記錄請求&響應標頭。你可以直接使用這個。

class LoggingInterceptor implements Interceptor { 
    @Override public Response intercept(Chain chain) throws IOException { 
    Request request = chain.request(); 

    long t1 = System.nanoTime(); 
    logger.info(String.format("Sending request %s on %s%n%s", 
     request.url(), chain.connection(), request.headers())); 

    Response response = chain.proceed(request); 

    long t2 = System.nanoTime(); 
    logger.info(String.format("Received response for %s in %.1fms%n%s", 
     response.request().url(), (t2 - t1)/1e6d, response.headers())); 

    return response; 
    } 
} 

要掛鉤它進行改造,您需要獲取Retrofit的預發佈快照。截至2015年1月,目前正在運送的Retrofit版本不參與OkHttp的攔截器。這個版本很快就會發布,但還沒有準備好。

+0

將Retrofit logging設置爲FULL將顯示傳入/傳出請求的標題,但我沒有在此處看到If-None-Match。它不顯示所有標題?如果是這樣,爲什麼? – AAverin 2015-01-04 10:02:04

+1

Retrofit不知道OkHttp的[獲得添加](https://github.com/square/okhttp/wiki/Calls)的頭文件,包括'Cache-Control'頭文件。 – 2015-01-05 04:09:58

+0

與@AAverin相同的問題,在改進日誌中沒有看到If-None-Match。感謝jesse-wilson,等待改進版發佈。 – crossle 2015-01-05 08:55:08

相關問題