简体   繁体   English

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

[英]Retrofit + RxJava fails to cache responses, suspected response headers

I'm trying to configure cache with Retrofit 1.9.0 and OkHtttp 2.5.0 . 我正在尝试使用Retrofit 1.9.0OkHtttp 2.5.0配置缓存。

Here is how I provide OkHttpClient for my RestAdapter : 这是我为OkHttpClient提供OkHttpClientRestAdapter

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

I did not forget to setClient on RestAdapter.Builder . 我没有忘记在RestAdapter.BuilderRestAdapter.Builder setClient Also made sure, that I'm actually using instance of RestAdapter with this client set. 还请确保,我实际上是将此客户端集与RestAdapter实例RestAdapter使用。

Even checked if the files are created under "http" folder. 甚至检查文件是否在“ http”文件夹下创建。 They are. 他们是。

However after I turn of WIFI and reload my screen I end up in OnError callback of Observable endpoint with this message: 但是,当我打开WIFI并重新加载屏幕后,最终在Observable端点的OnError回调中收到以下消息:

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

DISCLAIMER: I should probably mention that the final Observable is combined from 5 others, with flatMap and zip on the way. 免责声明:我可能应该提到,最终的Observable是由其他5个对象组成的,同时还有flatMapzip

I think I have an answer. 我想我有一个答案。 Short one is: "Cannot be done if server sends no-cache header in response". 简短的一个是:“如果服务器发送无缓存头作为响应,则无法完成”。

If you want the longer one, details are below. 如果您想要更长的一个,请在下面查看详细信息。

I've made a sample app comparing 2 backends. 我制作了一个比较2个后端的示例应用程序。 Lets call them Backend A, and Backend B. A was giving me troubles so I've decided to check on B. 我们称它们为后端A和后端B。A给我带来了麻烦,因此我决定检查B。

A returns CacheControl = "no-cache, no-transform, max-age=0" 返回CacheControl = "no-cache, no-transform, max-age=0"

B returns Cache-Control = „public" response header B返回Cache-Control = „public"响应头

I did the same setup for both backends, just different urls. 我为两个后端进行了相同的设置,只是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);
    }

Did both calls, then disabled wifi. 都打过电话,然后禁用了wifi。 Cache worked fine for B, but A thrown 504 Unsatisfiable Request (only-if-cached) 缓存对于B有效,但A抛出504 Unsatisfiable Request (only-if-cached)

It seems that overwritting headers won't help in that case. 在这种情况下,重写标题似乎无济于事。

You should rewrite your Request instead of the Response . 您应该重写您的Request而不是Response For reference, see the docs on rewriting requests . 作为参考,请参阅有关重写请求的文档。 Note you, can also use the CacheControl class instead of building your own header if you want. 请注意,如果需要,还可以使用CacheControl类代替构建自己的标头。 Your interceptor should look something like -- 您的拦截器应该看起来像-

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM