【问题标题】:Retrofit + RxJava fails to cache responses, suspected response headersRetrofit + RxJava 缓存响应失败,疑似响应头
【发布时间】:2015-12-13 00:44:42
【问题描述】:

我正在尝试使用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;
}

我没有忘记在RestAdapter.BuildersetClient。还要确定,我实际上是在这个客户端集上使用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 还在路上。

【问题讨论】:

标签: android caching retrofit okhttp rx-android


【解决方案1】:

我想我有一个答案。简短的是:“如果服务器发送无缓存标头作为响应,则无法完成”。

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

我制作了一个示例应用程序来比较 2 个后端。我们称它们为后端 A,后端 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 工作正常,但 A 抛出 504 Unsatisfiable Request (only-if-cached)

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

【讨论】:

    【解决方案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);
      }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-12-29
      • 2018-07-17
      • 2018-02-27
      • 2016-10-28
      • 2015-07-05
      • 2020-03-25
      • 2015-04-14
      相关资源
      最近更新 更多