OkHttp 3响应缓存异常:离线触发java.net.UnknownHostException
解决OkHttp离线缓存失效的问题
看起来你遇到的问题是明明配置了缓存,但离线时还是无法加载缓存数据,反而抛出了域名解析失败的错误。我来帮你分析下问题所在,然后一步步解决:
问题1:缓存目录配置错误
你现在用new File("cachedirectory")创建缓存目录,这个相对路径在Android环境下可能没有正确的写入权限,甚至根本创建失败,直接导致缓存没被保存下来。
修复方案:改用应用的内部缓存目录,既安全又能保证写入权限:
Cache provideOkHttpCache() { int cacheSize = 10 * 1024 * 1024; // 10 MiB // 使用App内部专属缓存目录 File cacheDir = new File(getApplicationContext().getCacheDir(), "http-cache"); Cache cache = new Cache(cacheDir, cacheSize); return cache; }
问题2:缓存拦截器的类型与逻辑有误
你当前用addInterceptor(应用拦截器)修改响应头,但这类拦截器会在所有请求流程中执行,包括离线缓存读取的场景。而且你没有区分有网络/无网络的缓存策略,导致离线时OkHttp还是尝试发起网络请求,最终报错。
正确的做法是用两个拦截器分工:
- 应用拦截器:处理离线场景,告诉OkHttp优先读取缓存
- 网络拦截器:仅在有网络时修改响应头,设置缓存有效期
调整拦截器代码:
// 网络拦截器:仅在网络请求成功返回时,设置缓存有效期 Interceptor cacheNetworkInterceptor = new Interceptor() { @Override public okhttp3.Response intercept(Chain chain) throws IOException { okhttp3.Response originalResponse = chain.proceed(chain.request()); // 有网络时,缓存有效期设为1天 return originalResponse.newBuilder() .header("Cache-Control", "public, max-age=86400") .build(); } }; // 应用拦截器:处理离线场景,强制读取缓存 Interceptor cacheAppInterceptor = new Interceptor() { @Override public okhttp3.Response intercept(Chain chain) throws IOException { Request request = chain.request(); // 无网络时,设置请求仅读取缓存,允许最长28天的过期缓存 if (!isNetworkAvailable(getApplicationContext())) { request = request.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=2419200") .build(); } return chain.proceed(request); } }; // 新增网络状态判断方法 private boolean isNetworkAvailable(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return activeNetworkInfo != null && activeNetworkInfo.isConnected(); }
然后在构建OkHttpClient时,注意拦截器的添加顺序:
OkHttpClient okHttpClient = new OkHttpClient() .newBuilder() .addInterceptor(httpLoggingInterceptor) .addInterceptor(cacheAppInterceptor) // 应用拦截器优先添加 .addNetworkInterceptor(cacheNetworkInterceptor) // 网络拦截器后添加 .cache(cache) .build();
问题3:必要权限缺失(必查)
如果你的应用运行在Android 6.0及以上系统,记得在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" />
验证缓存是否生效
你可以在onResponse中打印日志,确认缓存读取状态:
Log.v("cache-control", "是否来自缓存: " + isFromCache(response)); Log.v("cache-control", "缓存响应: " + response.raw().cacheResponse()); Log.v("cache-control", "网络响应: " + response.raw().networkResponse());
如果离线时cacheResponse不为null、networkResponse为null,就说明缓存生效了。
按照上面的步骤修改后,再重新测试离线场景:在线运行保存缓存→关闭应用开飞行模式→重启应用,就能正常加载缓存数据了。
内容的提问来源于stack exchange,提问作者Anton Prokopov
相关产品推荐
相关产品推荐

