2015-04-27 40 views
3

我知道有很多类似的问题,但我已经阅读了所有问题,但都没有帮助。Retrofit + OkHTTP - 响应缓存不能正常工作

所以,这里是我的问题:

我使用改装+ okhttp获取来自API的一些数据,我想对它们进行缓存。不幸的是,我没有管理员访问API服务器的权限,所以我不能修改服务器返回的头文件。 (目前,服务器返回缓存控制:私人)

所以我决定使用okhttp头欺骗来插入适当的缓存头。可悲的是,无论我做什么,缓存似乎都不起作用。

我初始化API服务是这样的:

int cacheSize = 10 * 1024 * 1024; // 10 MiB 
File cacheFile = new File(context.getCacheDir(), "thumbs"); 
final Cache cache = new Cache(cacheFile, cacheSize); 

OkHttpClient client = new OkHttpClient(); 
client.setCache(cache); 
client.interceptors().add(new Interceptor() { 
    @Override 
    public Response intercept(Chain chain) throws IOException { 
     Response originalResponse = chain.proceed(chain.request()); 
     return originalResponse.newBuilder() 
       .removeHeader("Access-Control-Allow-Origin") 
       .removeHeader("Vary") 
       .removeHeader("Age") 
       .removeHeader("Via") 
       .removeHeader("C3-Request") 
       .removeHeader("C3-Domain") 
       .removeHeader("C3-Date") 
       .removeHeader("C3-Hostname") 
       .removeHeader("C3-Cache-Control") 
       .removeHeader("X-Varnish-back") 
       .removeHeader("X-Varnish") 
       .removeHeader("X-Cache") 
       .removeHeader("X-Cache-Hit") 
       .removeHeader("X-Varnish-front") 
       .removeHeader("Connection") 
       .removeHeader("Accept-Ranges") 
       .removeHeader("Transfer-Encoding") 
       .header("Cache-Control", "public, max-age=60") 
       //.header("Expires", "Mon, 27 Apr 2015 08:15:14 GMT") 
       .build(); 
    } 
}); 

RestAdapter restAdapter = new RestAdapter.Builder() 
    .setEndpoint(API_ROOT) 
    .setLogLevel(RestAdapter.LogLevel.HEADERS_AND_ARGS) 
    .setClient(new OkClient(client)) 
    .setConverter(new SimpleXMLConverter(false)) 
    .setRequestInterceptor(new RequestInterceptor() { 
     @Override 
     public void intercept(RequestFacade request) { 
      if (Network.isConnected(context)) { 
       int maxAge = 60; // read from cache for 2 minutes 
       request.addHeader("Cache-Control", "public, max-age=" + maxAge); 
      } else { 
       int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale 
       request.addHeader("Cache-Control", 
        "public, only-if-cached, max-stale=" + maxStale); 
      } 
     } 
    }) 
    .build(); 
api = restAdapter.create(ApiService.class); 

当然,这是没有必要删除所有这些标题,但我想做出响应尽可能干净,以从这些额外排除一些干扰头。你可以看到,我试图欺骗过期和日期标题(我尝试删除它们,设置它们,以便它们之间确实存在最大年龄差异,并将过期设置到将来)。我也尝试了各种缓存控制值,但没有运气。

我确定cacheFile存在,isDirectory并且可由应用程序写入。

这些请求和响应头直接改装记录:

Request: 
Cache-Control: public, max-age=60 
---> END HTTP (no body) 

Response: 
Date: Mon, 27 Apr 2015 08:41:10 GMT 
Server: Apache/2.2.22 (Ubuntu) 
Expires: Mon, 27 Apr 2015 08:46:10 GMT 
Content-Type: text/xml; charset=UTF-8 
OkHttp-Selected-Protocol: http/1.1 
OkHttp-Sent-Millis: 1430124070000 
OkHttp-Received-Millis: 1430124070040 
Cache-Control: public, max-age=60 
<--- END HTTP (-1-byte body) 
<--- BODY: ... 

而且,最后一个奇怪的事件:在某些时候,缓存工作了几分钟。我得到了合理的命中数,即使离线请求返回缓存值。 (它发生在使用这里张贴的确切设置)但是当我重新启动应用程序,一切都回到“正常”(恒定命中数0)。如果任何人有任何想法可能是什么问题就在这里

合作,我会任何帮助:)

回答

8

使用networkInterceptors(),而不是拦截真的很高兴()。这与您的删除任何与缓存有关的头文件的策略相结合将会起作用。这是简短的答案。

当您使用拦截器更改标头时,它在调用CacheStrategy.isCacheable()之前不会进行任何调整。查看CacheStrategy和CacheControl类以查看OKHttp如何处理与缓存相关的标头是值得的。这也是值得做ctrl + f“缓存”http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

我不确定networkInterceptors()和interceptors()文档是否只是不清楚,或者如果有错误。一旦我看到更多,我会更新这个答案。

+1

哦,男孩,愚蠢的我。非常感谢你。我必须有某种时间性失明或某种东西 - 我从来没有意识到在那个代码中有inteceptors()而不是networkInterceptors()... – daemontus

7

除了Brendan Weinstein的回答,只是为了确认OkHttp3缓存将不适用于发布请求。