Retrofit + RxJava无法缓存响应,可疑响应标头

时间:2015-09-16 12:20:27

标签: android caching retrofit okhttp rx-android

我正在尝试使用Retrofit 1.9.0OkHtttp 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人组合而成的,flatMapzip正在途中。

2 个答案:

答案 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);
  }
});