如何在 Android 上使用 HttpsURLConnection 和 HttpResponseCache 强制缓存?
Posted
技术标签:
【中文标题】如何在 Android 上使用 HttpsURLConnection 和 HttpResponseCache 强制缓存?【英文标题】:How to force caching with HttpsURLConnection and HttpResponseCache on Android? 【发布时间】:2018-06-03 13:47:27 【问题描述】:我有以下方法从 wiktionary.org 请求页面,问题是服务器在标头中返回 Cache-control => private, must-revalidate, max-age=0
,这阻止了 HttpsURLConnection
存储请求。
有没有办法强制缓存这些页面?
protected static synchronized String getUrlContent(String url) throws ApiException
if (sUserAgent == null)
throw new ApiException("User-Agent string must be prepared");
try
URL obj = new URL(url);
HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("User-Agent", sUserAgent);
//connection.addRequestProperty("Cache-Control", "max-stale");
//connection.addRequestProperty("Cache-Control", "public, max-age=3600");
//connection.addRequestProperty("Cache-Control", "only-if-cached");
int responseCode = connection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) // success
throw new ApiException("Invalid response from server: " + responseCode);
InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream content = new ByteArrayOutputStream();
// Read response into a buffered stream
int readBytes = 0;
while ((readBytes = inputStream.read(sBuffer)) != -1)
content.write(sBuffer, 0, readBytes);
HttpResponseCache cache = HttpResponseCache.getInstalled();
if (cache != null)
Log.w("!!!", "Cache hit count: " + cache.getHitCount());
//connection.addRequestProperty("Cache-Control", "public, max-age=3600");
Log.w("!!!", "Cache-Control: " + connection.getHeaderField("Cache-Control"));
//cache.put(new URI(url), connection);
// Return result from buffered stream
return new String(content.toByteArray());
catch (Exception e)
throw new ApiException("Problem communicating with API", e);
更新:
仍然无法通过okhttp interceptors 获得缓存命中
static private OkHttpClient client;
static private Cache cache;
public static OkHttpClient getClient()
if (client == null)
File cacheDirectory = new File(App.getInstance().getCacheDir().getAbsolutePath(), "HttpCache");
cache = new Cache(cacheDirectory, 1024 * 1024);
client = new OkHttpClient.Builder()
.cache(cache)
.addInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR).build();
return client;
/** Dangerous interceptor that rewrites the server's cache-control header. */
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor()
@Override public Response intercept(Interceptor.Chain chain) throws IOException
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.header("Cache-Control", "max-age=60")
.build();
;
protected static synchronized String getUrlContent(String url) throws ApiException
try
OkHttpClient httpClient = getClient();
Request request = new Request.Builder()
.url(url)
.build();
Response response = httpClient.newCall(request).execute();
Log.w("!!!", "hitCount: " + cache.hitCount());
return response.body().string();
catch (Exception e)
throw new ApiException("Problem communicating with API", e);
【问题讨论】:
为什么不自己缓存它们,在 HTTP 请求层之上(例如,在您的存储库中)? @CommonsWare 如果我将域更改为支持缓存的其他站点,那么我需要检查缓存命中,以免自己缓存数据。似乎HttpsURLConnection
和HttpResponseCache
都没有办法检查。另外,我在想也许我可以更改连接对象中的标头并将其存储在缓存中,就像cache.put(uri, connection);
一样,但似乎不可能。
“如果我将域更改为支持缓存的其他站点,那么我需要检查缓存命中,以免自己缓存数据”——或者,告诉 HTTP 堆栈不缓存,在应用层处理。我不知道HttpsURLConnection
是否提供,尽管 OkHttp 提供。可能有一个 OkHttp 配置可以处理您的目标,尽管我在快速扫描中没有看到。
@CommonsWare 用 okhttp 更新了我的问题,但仍然无法获得缓存命中。
【参考方案1】:
初始化 OKHttpClient 时请使用addNetworkInterceptor
而不是addInterceptor
重写缓存控制。
【讨论】:
我可以将User-Agent
放在同一个拦截器中,还是需要第二个,然后用addInterceptor
代替?
为什么需要user-agent
的拦截器?只需在构建请求时添加即可。
我明白了,你的意思是Request.Builder().addHeader()
...这样就可以了,谢谢。以上是关于如何在 Android 上使用 HttpsURLConnection 和 HttpResponseCache 强制缓存?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 上使用 javax.smartcardio 包?