Retrofit + RxJava 缓存响应失败,疑似响应头

Retrofit + RxJava fails to cache responses, suspected response headers

我正在尝试使用 Retrofit 1.9.0OkHtttp 2.5.0 配置缓存。

这是我为 RestAdapter 提供 OkHttpClient 的方式:

@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 并重新加载我的屏幕后,我最终在 Observable 端点的 OnError 回调中收到以下消息:

retrofit.RetrofitError: failed to connect to /10.40.31.12 (port 8888) after 10000ms: connect failed: ENETUNREACH (Network is unreachable)

免责声明:我应该提一下,最后的 Observable 是由其他 5 个组合而成的,还有 flatMapzip

您应该重写 Request 而不是 Response。作为参考,请参阅 rewriting requests. Note you, can also use the CacheControl class 上的文档,而不是根据需要构建自己的 header。您的拦截器应该类似于 --

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

我想我有答案了。短的一个是:"Cannot be done if server sends no-cache header in response"。

如果你想要更长的,详情如下。

我制作了一个比较 2 个后端的示例应用程序。让我们称它们为后端 A 和后端 B。A 给我带来了麻烦,所以我决定检查 B。

一个returnsCacheControl = "no-cache, no-transform, max-age=0"

B returns Cache-Control = „public" 回复 header

我对两个后端进行了相同的设置,只是 url 不同。

    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 的缓存工作正常,但 A 抛出 504 Unsatisfiable Request (only-if-cached)

在这种情况下,覆盖 headers 似乎无济于事。