使用Retrofit 2.0.x进行HTTPcaching

我试图使用Retrofit 2.0在我的应用程序中caching一些响应,但我错过了一些东西。

我安装了一个caching文件如下:

private static File httpCacheDir; private static Cache cache; try { httpCacheDir = new File(getApplicationContext().getCacheDir(), "http"); httpCacheDir.setReadable(true); long httpCacheSize = 10 * 1024 * 1024; // 10 MiB HttpResponseCache.install(httpCacheDir, httpCacheSize); cache = new Cache(httpCacheDir, httpCacheSize); Log.i("HTTP Caching", "HTTP response cache installation success"); } catch (IOException e) { Log.i("HTTP Caching", "HTTP response cache installation failed:" + e); } public static Cache getCache() { return cache; } 

/data/user/0/<PackageNmae>/cache/http中创build一个文件,然后准备一个networking拦截器,如下所示:

 public class CachingControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // Add Cache Control only for GET methods if (request.method().equals("GET")) { if (ConnectivityUtil.checkConnectivity(getContext())) { // 1 day request.newBuilder() .header("Cache-Control", "only-if-cached") .build(); } else { // 4 weeks stale request.newBuilder() .header("Cache-Control", "public, max-stale=2419200") .build(); } } Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder() .header("Cache-Control", "max-age=86400") .build(); } } 

我的RetrofitOkHttpClient实例:

 OkHttpClient client = new OkHttpClient(); client.setCache(getCache()); client.interceptors().add(new MainInterceptor()); client.interceptors().add(new LoggingInceptor()); client.networkInterceptors().add(new CachingControlInterceptor()); Retrofit restAdapter = new Retrofit.Builder() .client(client) .baseUrl(Constants.BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .build(); productsService = restAdapter.create(ProductsService.class); 

其中ProductsService.class包含:

 @Headers("Cache-Control: max-age=86400") @GET("categories/") Call<PagedResponse<Category>> listCategories(); 

 Call<PagedResponse<Category>> call = getRestClient().getProductsService().listCategories(); call.enqueue(new GenericCallback<PagedResponse<Category>>() { // whatever // GenericCallback<T> implements Callback<T> } }); 

这里的问题是:如何使设备脱机时访问caching的响应?

后端响应标题是:

 Allow → GET, HEAD, OPTIONS Cache-Control → max-age=86400, must-revalidate Connection → keep-alive Content-Encoding → gzip Content-Language → en Content-Type → application/json; charset=utf-8 Date → Thu, 17 Dec 2015 09:42:49 GMT Server → nginx Transfer-Encoding → chunked Vary → Accept-Encoding, Cookie, Accept-Language X-Frame-Options → SAMEORIGIN x-content-type-options → nosniff x-xss-protection → 1; mode=block 

Solutions Collecting From Web of "使用Retrofit 2.0.x进行HTTPcaching"

最后我得到答案。

networking拦截器应该如下:

 public class CachingControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // Add Cache Control only for GET methods if (request.method().equals("GET")) { if (ConnectivityUtil.checkConnectivity(YaootaApplication.getContext())) { // 1 day request = request.newBuilder() .header("Cache-Control", "only-if-cached") .build(); } else { // 4 weeks stale request = request.newBuilder() .header("Cache-Control", "public, max-stale=2419200") .build(); } } Response originalResponse = chain.proceed(request); return originalResponse.newBuilder() .header("Cache-Control", "max-age=600") .build(); } } 

那么安装caching文件就是这么简单的

 long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB Cache cache = new Cache(new File(context.getCacheDir(), "http"), SIZE_OF_CACHE); OkHttpClient client = new OkHttpClient(); client.cache(cache); client.networkInterceptors().add(new CachingControlInterceptor()); 

CachingControlInterceptor ,您创build了新的请求,但从来没有真正使用它们。 你调用newBuilder并忽略结果,所以头修改从来没有实际发送到任何地方。 尝试分配这些值request ,然后而不是调用proceedchain.request()调用它的request

 public class CachingControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // Add Cache Control only for GET methods if (request.method().equals("GET")) { if (ConnectivityUtil.checkConnectivity(getContext())) { // 1 day request = request.newBuilder() .header("Cache-Control", "only-if-cached") .build(); } else { // 4 weeks stale request = request.newBuilder() .header("Cache-Control", "public, max-stale=2419200") .build(); } } Response originalResponse = chain.proceed(request); return originalResponse.newBuilder() .header("Cache-Control", "max-age=600") .build(); } } 

你也可以尝试:

 public class CachingInterceptor implements Interceptor { @Override public okhttp3.Response intercept(Chain chain) throws IOException { Request request = chain.request(); request = new Request.Builder() .cacheControl(new CacheControl.Builder() .maxAge(1, TimeUnit.DAYS) .minFresh(4, TimeUnit.HOURS) .maxStale(8, TimeUnit.HOURS) .build()) .url(request.url()) .build(); return chain.proceed(request); } } 

我终于在Retrofit 2.x和OkHttp 3.x中发现了解决scheme

我必须实现两个拦截器 ,其中一个负责重写请求头 ,另一个负责重写Response头

  1. 首先,确保你删除了旧的caching。 (根资源pipe理器/data/data/com.yourapp/cache

  2. 实例化客户端构build器:

     OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder() .cache(cache) .addInterceptor(new RewriteRequestInterceptor()) .addNetworkInterceptor(new RewriteResponseCacheControlInterceptor()) 
  3. 创buildRewriteRequestInterceptor

     public class RewriteRequestInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { int maxStale = 60 * 60 * 24 * 5; Request request; if (NetworkUtils.isNetworkAvailable()) { request = chain.request(); } else { request = chain.request().newBuilder().header("Cache-Control", "max-stale=" + maxStale).build(); } return chain.proceed(request); } } 
  4. 创buildRewriteResponseCacheControlInterceptor

     public class RewriteResponseCacheControlInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { int maxStale = 60 * 60 * 24 * 5; Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder().header("Cache-Control", "public, max-age=120, max-stale=" + maxStale).build(); } } 

确保将ResponseCacheControlInterceptor添加为networking拦截器,将RewriteRequestInterceptor添加为拦截器(正如我在第二步中所做的),这一点非常重要。

  OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();