检测 OkHttp 响应是否来自缓存(使用 Retrofit)
Detect if OkHttp response comes from cache (with Retrofit)
有没有办法检测 Retrofit 响应是来自配置的 OkHttp 缓存还是实时响应?
客户定义:
Cache cache = new Cache(getCacheDirectory(context), 1024 * 1024 * 10);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
.build();
Api定义:
@GET("/object")
Observable<Result<SomeObject>> getSomeObject();
调用示例:
RetroApi retroApi = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RetroApi.class);
result = retroApi.getSomeObject().subscribe((Result<SomeObject> someObjectResult) -> {
isFromCache(someObjectResult); // ???
});
解决方案一:
通过使用 okhttp3.Response.cacheResponse() 您可以检查是否从缓存中收到了响应:
Returns the raw response received from the cache. Will be null if this response didn't use the cache
要从改造响应对象获取原始 OkHttp 响应,请使用 .raw()
。即:
public boolean isFromCache(Result<?> retroResult) {
return retroResult.response().raw().cacheResponse() != null;
}
解决方案二:
您可以通过 new OkHttpClient.Builder().addInterceptor(...)
向 OkHttp 客户端添加拦截器。
在此拦截器中,通过 chain.proceed(chain.request)
检索响应。
然后分别用Response.cacheResponse()
Response.networkResponse()
判断响应来自哪里
完整代码:
new OkHttpClient.Builder().addInterceptor(chain -> {
Response response = chain.proceed(chain.request());
if (response.cacheControl() != null) {
// from cache
} else if (response.networkResponse() != null) {
// from network
}
return response;
});
任何时候你有 okhttp3.Response
(retrofit2.Response.raw()
),你可以检查响应是否来自缓存。
引用杰西·威尔逊的话:
There are a few combos.
.networkResponse() only – your request was served from network exclusively.
.cacheResponse() only – your request was served from cache exclusively.
.networkResponse() and .cacheResponse() – your request was a conditional GET, so headers are from the network and body is from the cache.
因此,对于您的示例,isFromCache
方法如下所示:
boolean isFromCache(Result<?> result) {
return result.response().raw().networkResponse() == null;
}
if (response.raw().cacheResponse() != null) {
// true: response was served from cache
}
if (response.raw().networkResponse() != null) {
// true: response was served from network/server
}
但我建议您检查您的 networkResponse 是否为 null,因为一旦请求被缓存并且您也有 networkResponse,您的响应通过流向下传递是来自网络而不是缓存(取决于 maxStale 你可能已在 CacheControl 上指定)。因此,请检查 networkResponse 是否不为空,如果为空且您的 cacheResponse 不为空,则响应从缓存提供,反之亦然。
为时已晚,但也许这对某人有帮助。当内容来自网络时:response.networkResponse()
和response.cacheResponse()
不为空,当内容来自缓存时response.networkResponse()
为空,所以来自@sebastian的代码:
new OkHttpClient.Builder().addInterceptor(chain -> {
Response response = chain.proceed(chain.request());
if (response.cacheControl() != null) {
// from cache
} else if (response.networkResponse() != null) {
// from network
}
return response;
});
只需替换为此代码:
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(new Interceptor() {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
if (response.networkResponse() != null) {
Log.v(TAG, "Response from networkResponse(): " + response.networkResponse());
} else if (response.cacheResponse() != null) {
Log.v(TAG, "Response from cacheControl(): " + response.cacheResponse());
}
return response;
}
});
如果 cacheResponse 存在,则响应来自缓存 AND networkResponse(如果存在)的响应代码为 304。参见:https://github.com/square/okhttp/issues/4539
有没有办法检测 Retrofit 响应是来自配置的 OkHttp 缓存还是实时响应?
客户定义:
Cache cache = new Cache(getCacheDirectory(context), 1024 * 1024 * 10);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
.build();
Api定义:
@GET("/object")
Observable<Result<SomeObject>> getSomeObject();
调用示例:
RetroApi retroApi = new Retrofit.Builder()
.client(okHttpClient)
.baseUrl(baseUrl)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(RetroApi.class);
result = retroApi.getSomeObject().subscribe((Result<SomeObject> someObjectResult) -> {
isFromCache(someObjectResult); // ???
});
解决方案一:
通过使用 okhttp3.Response.cacheResponse() 您可以检查是否从缓存中收到了响应:
Returns the raw response received from the cache. Will be null if this response didn't use the cache
要从改造响应对象获取原始 OkHttp 响应,请使用 .raw()
。即:
public boolean isFromCache(Result<?> retroResult) {
return retroResult.response().raw().cacheResponse() != null;
}
解决方案二:
您可以通过 new OkHttpClient.Builder().addInterceptor(...)
向 OkHttp 客户端添加拦截器。
在此拦截器中,通过 chain.proceed(chain.request)
检索响应。
然后分别用Response.cacheResponse()
Response.networkResponse()
判断响应来自哪里
完整代码:
new OkHttpClient.Builder().addInterceptor(chain -> {
Response response = chain.proceed(chain.request());
if (response.cacheControl() != null) {
// from cache
} else if (response.networkResponse() != null) {
// from network
}
return response;
});
任何时候你有 okhttp3.Response
(retrofit2.Response.raw()
),你可以检查响应是否来自缓存。
引用杰西·威尔逊的话:
There are a few combos.
.networkResponse() only – your request was served from network exclusively.
.cacheResponse() only – your request was served from cache exclusively.
.networkResponse() and .cacheResponse() – your request was a conditional GET, so headers are from the network and body is from the cache.
因此,对于您的示例,isFromCache
方法如下所示:
boolean isFromCache(Result<?> result) {
return result.response().raw().networkResponse() == null;
}
if (response.raw().cacheResponse() != null) {
// true: response was served from cache
}
if (response.raw().networkResponse() != null) {
// true: response was served from network/server
}
但我建议您检查您的 networkResponse 是否为 null,因为一旦请求被缓存并且您也有 networkResponse,您的响应通过流向下传递是来自网络而不是缓存(取决于 maxStale 你可能已在 CacheControl 上指定)。因此,请检查 networkResponse 是否不为空,如果为空且您的 cacheResponse 不为空,则响应从缓存提供,反之亦然。
为时已晚,但也许这对某人有帮助。当内容来自网络时:response.networkResponse()
和response.cacheResponse()
不为空,当内容来自缓存时response.networkResponse()
为空,所以来自@sebastian的代码:
new OkHttpClient.Builder().addInterceptor(chain -> {
Response response = chain.proceed(chain.request());
if (response.cacheControl() != null) {
// from cache
} else if (response.networkResponse() != null) {
// from network
}
return response;
});
只需替换为此代码:
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
okHttpClientBuilder.addInterceptor(new Interceptor() {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
if (response.networkResponse() != null) {
Log.v(TAG, "Response from networkResponse(): " + response.networkResponse());
} else if (response.cacheResponse() != null) {
Log.v(TAG, "Response from cacheControl(): " + response.cacheResponse());
}
return response;
}
});
如果 cacheResponse 存在,则响应来自缓存 AND networkResponse(如果存在)的响应代码为 304。参见:https://github.com/square/okhttp/issues/4539