我正在尝试使用Retrofit 1.9.0
和OkHtttp 2.5.0
配置缓存。
以下是我为OkHttpClient
提供RestAdapter
的方式:
@Provides
@Singleton
public OkHttpClient provideOkHttpClient() {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
okHttpClient.setWriteTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
File cacheDir = new File(context.getCacheDir(), "http");
final Cache cache = new Cache(cacheDir, DISK_CACHE_SIZE_IN_BYTES);
okHttpClient.setCache(cache);
okHttpClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(request);
Response finalResponse = response.newBuilder()
.header("Cache-Control", String.format("public, max-stale=%d", 604800))
.build();
Log.d("OkHttp", finalResponse.toString());
Log.d("OkHttp Headers", finalResponse.headers().toString());
return finalResponse;
}
});
return okHttpClient;
}
我没有忘记setClient
上的RestAdapter.Builder
。还确定,我实际上正在使用此客户端集RestAdapter
的实例。
甚至检查文件是否在“http”文件夹下创建。他们是。
然而,在我关闭WIFI并重新加载屏幕后,我最终在OnError
端点Observable
回调了这条消息:
retrofit.RetrofitError: failed to connect to /10.40.31.12 (port 8888) after 10000ms: connect failed: ENETUNREACH (Network is unreachable)
免责声明:我应该提一下,最终的Observable
是由其他5人组合而成的,flatMap
和zip
正在途中。
答案 0 :(得分:3)
我想我有一个答案。简短的一个是:"如果服务器在响应"中发送no-cache标头,则无法完成。
如果你想要更长的一个,详细信息如下。
我做了一个比较2个后端的示例应用程序。让我们称他们为Backend A和Backend B. A给了我麻烦所以我决定检查B。
A返回CacheControl = "no-cache, no-transform, max-age=0"
B返回Cache-Control = „public"
响应标题
我为两个后端做了相同的设置,只是不同的网址。
private void buildApi() {
Gson gson = new GsonBuilder().create();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
File cacheDir = new File(getCacheDir(), "http");
final Cache cache = new Cache(cacheDir, 1000000 * 10);
okHttpClient.setCache(cache);
okHttpClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Log.d("OkHttp REQUEST", request.toString());
Log.d("OkHttp REQUEST Headers", request.headers().toString());
Response response = chain.proceed(request);
response = response.newBuilder()
.header("Cache-Control", String.format("public, max-age=%d, max-stale=%d", 60, RESPONSE_CACHE_LIFESPAN_IN_SECONDS))
.build();
Log.d("OkHttp RESPONSE", response.toString());
Log.d("OkHttp RESPONSE Headers", response.headers().toString());
return response;
}
});
RestAdapter.Builder builder = new RestAdapter.Builder()
.setConverter(new StringGsonConverter(gson))
.setClient(new OkClient(okHttpClient))
.setRequestInterceptor(new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
if (isNetworkAvailable()) {
request.addHeader("Cache-Control", "public, max-age=" + 60);
} else {
request.addHeader("Cache-Control", "public, only-if-cached, max-stale=" + RESPONSE_CACHE_LIFESPAN_IN_SECONDS);
}
}
});
builder.setEndpoint("http://this.is.under.vpn.so.wont.work.anyway/api");
A_API = builder.build().create(AApi.class);
builder.setEndpoint("http://collector-prod-server.elasticbeanstalk.com/api");
B_API = builder.build().create(BApi.class);
}
两个电话,然后禁用wifi。
缓存适用于B,但抛出504 Unsatisfiable Request (only-if-cached)
在这种情况下,覆盖标题似乎不会有所帮助。
答案 1 :(得分:2)
您应该重写Request
而不是Response
。有关参考,请参阅rewriting requests上的文档。请注意,如果需要,也可以使用CacheControl
类而不是构建自己的标题。你的拦截器应该看起来像 -
okHttpClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request cachedRequest = request.newBuilder()
.cacheControl(new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build())
.build();
return chain.proceed(cachedRequest);
}
});