【发布时间】:2016-12-20 15:06:39
【问题描述】:
我正在尝试使用 Retrofit (2.1.0) 和 OkHttp (3.3.1) 设置 HTTP 缓存。我看过很多与这个主题相关的帖子,但都没有帮助。
我写了一些单元测试来看看缓存是如何工作的。它工作得很好,但是一旦集成到我的应用程序中,魔法就结束了。我将首先向您展示我的实现,然后解释我的一些调查。
首先,这是我的改造实例:
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
OkHttpClient client = httpBuilder
.addNetworkInterceptor(INTERCEPTOR_RESPONSE_SET_CACHE)
.addNetworkInterceptor(INTERCEPTOR_REQUEST_ADD_CHECKSUM)
.addInterceptor(loggingInterceptor)
.cache(cacheHttpClient).build();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl(BASE_URL)
.build();
这里是拦截器添加一个标头来设置缓存控制:
private final Interceptor INTERCEPTOR_RESPONSE_SET_CACHE = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
response = response.newBuilder()
.header("Cache-Control", "max-age=600") //+ Integer.toString(3600 * 5)
.build();
return response;
}
};
最后一个拦截器添加2个URL参数:
private static final Interceptor INTERCEPTOR_REQUEST_ADD_CHECKSUM = new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
HttpUrl url = chain.request().url();
url = url.newBuilder().addQueryParameter("rd", "random1").addQueryParameter("chk","check1").build();
Request request = chain.request().newBuilder().url(url).build();
return chain.proceed(request);
}
};
最后,我的服务的单一方法:
@Headers("Cache-Control: public, max-stale=500")
@GET("/get_data")
Call<DataResponse> getData(@Query("year") int year, @Query("month") int month, @Query("day") int day);
关于我的调查,我设置了一个拦截器记录器(应用端,而不是网络)来查看发生了什么。我可以在我的日志中看到诸如“Cache-Control: public, max-stale=500”之类的行。这意味着(至少对我而言)标头应该让 OkHttp 客户端有机会检查缓存。
缓存本身似乎已正确初始化。当我创建它时,我强制初始化并记录缓存中存在的所有 url。以下是它的实现方式:
File httpCacheDirectory = new File(getCacheDir(), "responses");
httpCacheDirectory.getParentFile().mkdirs();
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(httpCacheDirectory, cacheSize);
try {
cache.initialize();
Iterator<String> iterator = cache.urls();
Log.i(TAG, "URLs in cacheHttpClient : ");
while (iterator.hasNext()) {
Log.i(TAG, iterator.next());
}
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "CACHE NOT INIT");
}
当我在 Wifi 可用的情况下启动我的应用时,我得到了预期的响应。然后我杀死我的应用程序,禁用 Wifi 并重新启动应用程序。我希望缓存此时可以提供数据。但它失败了,我只能在日志中看到 OkHttp 打印行:
HTTP 失败:java.net.UnknownHostException:无法解析主机 “my-domain.com”:没有与主机名关联的地址
最后一件事,RFC 2616,可以阅读:
max-stale :表示客户端愿意接受响应 已超过其到期时间。如果 max-stale 被分配一个 值,则客户端愿意接受具有 超过其到期时间不超过指定数量 秒。如果没有为 max-stale 赋值,那么客户端是 愿意接受任何年龄的陈旧回应。
当我没有指定一个值时,它确实有效(即使 Wifi 关闭,我也会收到响应)。目前,这是我发现使其“工作”的唯一方法。所以也许我只是误解了缓存控制指令!?
在这一点上,我真的很困惑。我真的很想能够使用 OkHttp 缓存系统,但不知怎的,我错过了一些东西。
感谢您阅读所有文字!
【问题讨论】:
标签: android caching retrofit2 okhttp3