You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的Cache API手动检查缓存是否存在:
val cache = okHttpClient.cache()
val cacheResponse = cache?.get(request)
Log.d("CacheDebug", "缓存是否存在:${cacheResponse != null},缓存响应码:${cacheResponse?.code}")
  • 查看context.cacheDir下的OkHttp缓存文件,确认响应确实被缓存

内容的提问来源于stack exchange,提问作者Expiredmind

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 11:16:20