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

Swift中使用URLCache缓存API响应及请求失效问题排查

问题分析与修复方案

你的GET API已配置合规的缓存响应头,但iOS客户端仍无法正常缓存响应,结合服务器响应头和客户端代码,以下是核心问题和修复步骤:

1. 错误的缓存目录路径

你的CacheManager将缓存目录设置在了Documents目录下,而iOS中URLCache的标准缓存路径应为Library/Caches目录。Documents目录用于存储用户可直接访问的数据,系统对该目录的缓存行为有特殊限制,可能导致URLCache无法正常读写缓存。

修复代码:

class CacheManager {
    static let shared = CacheManager()
    let cache: URLCache
    let session: URLSession

    private init() {
        // 使用Library/Caches下的子目录存储缓存
        let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
            .appendingPathComponent("api-cache")
        cache = URLCache(memoryCapacity: 16 * 1024 * 1024, diskCapacity: 80 * 1024 * 1024, diskPath: cacheDir.path)
        
        let configuration = URLSessionConfiguration.default
        configuration.urlCache = cache
        configuration.requestCachePolicy = .returnCacheDataElseLoad
        session = URLSession(configuration: configuration)
    }
}

2. 重复创建URLSession实例

每次调用fetch函数时都新建URLSession实例,不仅浪费资源,还可能导致缓存逻辑不一致。建议复用同一个URLSession实例。

修复代码(整合到上述CacheManager):
在CacheManager中提前初始化并复用URLSession,避免每次请求新建。

3. 手动缓存的冗余操作

你手动调用storeCachedResponse存储缓存,但URLSession会根据请求缓存策略和服务器响应头自动处理缓存逻辑,手动存储可能干扰系统的自动缓存机制,导致缓存无法被正确读取。

修复:
移除手动存储缓存的代码,让URLSession遵循HTTP缓存规则自动处理缓存。

4. 缓存命中后的逻辑缺失

原代码中缓存命中后仅打印日志,未调用completion返回缓存数据,导致调用方无法感知缓存命中,误以为缓存未生效。

修复后的fetch函数:

func fetch(filters:[String:Any] = [:], completion: @escaping (Result<[Model], Error>) -> Void) {
    guard let url = URL(string: apiURL) else {
        completion(.failure(NSError(domain: "APIError", code: -2, userInfo: [NSLocalizedDescriptionKey: "Invalid API URL"])))
        return
    }
    
    var request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad)
    request.httpMethod = "GET"
    request.timeoutInterval = 60

    // 检查缓存命中
    if let cachedResponse = CacheManager.shared.cache.cachedResponse(for: request) {
        print("Cache hit! Data size: \(cachedResponse.data.count) bytes")
        // 解析缓存数据并回调
        do {
            let model = try JSONDecoder().decode(Model.self, from: cachedResponse.data)
            completion(.success(model.Model))
        } catch {
            completion(.failure(error))
        }
        return
    }
    
    // 无缓存时发起请求
    CacheManager.shared.session.dataTask(with: request) { (data, response, error) in
        DispatchQueue.main.async {
            if let error = error {
                completion(.failure(error))
                return
            }
            
            guard let data = data, let response = response as? HTTPURLResponse else {
                completion(.failure(NSError(domain: "APIError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid data or response"])))
                return
            }
            
            if response.statusCode != 200 {
                completion(.failure(NSError(domain: "APIError", code: response.statusCode, userInfo: [NSLocalizedDescriptionKey: "API error: \(response.statusCode)"])))
                return
            }
            
            do {
                let model = try JSONDecoder().decode(Model.self, from: data)
                completion(.success(model.Model))
            } catch {
                completion(.failure(error))
            }
        }
    }.resume()
}

额外验证点

  • 确认apiURL每次请求完全一致,动态参数需正确包含在URL中,确保URLCache能匹配缓存键。
  • 检查设备存储空间,若磁盘不足,URLCache会自动跳过缓存存储。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:15:51