OkHttp缓存系统失效:504 Unsatisfiable Request (only-if-cached)问题求助
问题诊断与修复方案
1. 确认请求方法为GET
OkHttp默认仅缓存GET请求,如果你的请求是POST/PUT等非GET方法,哪怕设置了缓存头也不会被缓存。得检查你的请求方法是否为GET,非GET请求不推荐做缓存,风险较高。
2. 修正应用拦截器的缓存 fallback 逻辑
当前应用拦截器在网络失败时发起FORCE_CACHE请求,存在两个隐患:
- 网络请求抛异常后重新发起的请求,缓存key可能和原请求不匹配(比如原请求带动态Header)
- 更稳妥的方式是直接从OkHttp的Cache里读缓存,而非再次发起请求
修改应用拦截器代码:
override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() return try { chain.proceed(request) } catch (e: Exception) { when (e) { is ServerError, is SocketTimeoutException, is TimeoutException, is ConnectException -> { // 直接读取缓存,无需重新请求 val cache = chain.call().client.cache() ?: throw e val cacheResponse = cache.get(request) cacheResponse ?: throw e // 确实无缓存再抛原异常 } else -> throw e } } }
3. 检查拦截器添加顺序
OkHttp的拦截器顺序不能乱:先加应用拦截器,后加网络拦截器。顺序颠倒会导致缓存头的修改逻辑失效。确保OkHttpClient配置里的拦截器顺序正确:
fun getOkHttpClient(context: Context): OkHttpClient { val appCache = Cache(context.cacheDir, CACHE_MAX_SIZE) val appInterceptor = YourAppInterceptor() val networkInterceptor = YourNetworkInterceptor() return OkHttpClient.Builder() .cache(appCache) .connectTimeout(CONNECT_TIMEOUT_SEC, TimeUnit.SECONDS) .addInterceptor(appInterceptor) // 应用拦截器先添加 .addNetworkInterceptor(networkInterceptor) // 网络拦截器后添加 .build().apply { dispatcher.maxRequestsPerHost = 1 } }
4. 验证缓存头格式正确性
确保HeadersFields.getPublicMaxAgeHeader(3600)返回标准格式的Cache-Control头:"public, max-age=3600"。可以临时换成硬编码值测试:
.header( HeadersFields.CACHE_CONTROL, "public, max-age=3600" // 替换原方法调用,验证格式是否正确 )
5. 排查缓存key不匹配问题
如果请求里带动态Header(比如Authorization、User-Agent或自定义Header),OkHttp会把这些Header作为缓存key的一部分。如果网络请求和缓存读取请求的Header不一致,就会命中不了缓存。要确保:
- 原请求和缓存读取请求的Header完全一致(除了Cache-Control)
- 若不需要某些Header参与缓存key计算,可在网络拦截器里移除这些Header后再缓存响应
额外验证步骤
- 用OkHttp的
CacheAPI手动检查缓存是否存在:
val cache = okHttpClient.cache() val cacheResponse = cache?.get(request) Log.d("CacheDebug", "缓存是否存在:${cacheResponse != null},缓存响应码:${cacheResponse?.code}")
- 查看
context.cacheDir下的OkHttp缓存文件,确认响应确实被缓存
内容的提问来源于stack exchange,提问作者Expiredmind
相关产品推荐
相关产品推荐

