You need to enable JavaScript to run this app. 使用Alamofire的ResponseCacher无法按2小时有效期获取缓存响应
优惠活动
大模型
产品
解决方案
定价
更多

使用Alamofire的ResponseCacher无法按2小时有效期获取缓存响应

问题原因
  • 你当前代码存在三个核心问题:
    1. 初始化CachedURLResponse时传入的userInfo变量未定义,会导致运行时错误,修改后的缓存响应无法正常写入缓存
    2. 系统默认的.useProtocolCachePolicy策略在离线场景下,会尝试向服务端验证缓存有效性,验证失败就不会返回缓存内容
    3. 仅设置Cache-Control头兼容性不足,部分系统版本的URLCache会优先读取Expires头判断缓存有效性,缺失该头会导致缓存过期逻辑失效
修正方案

1. 修正缓存响应构造扩展

extension CachedURLResponse {
    func response(with expirationDuration: TimeInterval) -> CachedURLResponse {
        guard let httpResponse = response as? HTTPURLResponse,
              let url = httpResponse.url,
              var headers = httpResponse.allHeaderFields as? [String: String] else {
            return self
        }
        // 同时设置Cache-Control和Expires,兼容不同系统版本的缓存判断
        headers["Cache-Control"] = "max-age=\(expirationDuration), private"
        headers.removeValue(forKey: "s-maxage")
        // 生成Expires头:当前时间加有效期,转成标准RFC1123格式
        let expirationDate = Date().addingTimeInterval(expirationDuration)
        let dateFormatter = DateFormatter()
        dateFormatter.locale = Locale(identifier: "en_US_POSIX")
        dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
        dateFormatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss zzz"
        headers["Expires"] = dateFormatter.string(from: expirationDate)
        // 把过期时间存到userInfo里,方便后续自定义判断
        var userInfo = self.userInfo ?? [:]
        userInfo["customExpirationDate"] = expirationDate
        
        guard let newHttpResponse = HTTPURLResponse(
            url: url,
            statusCode: httpResponse.statusCode,
            httpVersion: "HTTP/1.1",
            headerFields: headers
        ) else {
            return self
        }
        return CachedURLResponse(
            response: newHttpResponse,
            data: data,
            userInfo: userInfo,
            storagePolicy: .allowed
        )
    }
}

2. 修正会话初始化代码

let sessionConfiguration = URLSessionConfiguration.af.default
// 全局默认用协议缓存策略,在线场景下生效
sessionConfiguration.requestCachePolicy = .useProtocolCachePolicy
sessionConfiguration.urlCache = URLCache(
    memoryCapacity: 20 * 1024 * 1024, // 20MB内存缓存
    diskCapacity: 100 * 1024 * 1024 // 100MB磁盘缓存
)
let responseCacher = ResponseCacher(behavior: .modify { _, response in
    return CachedURLResponse(
        response: response.response,
        data: response.data,
        userInfo: nil,
        storagePolicy: .allowed
    ).response(with: 7200) // 2小时有效期
})

3. 添加请求拦截器适配离线场景

通过拦截器动态调整缓存策略,离线时直接返回缓存内容:

// 定义请求拦截器
class CacheInterceptor: RequestInterceptor {
    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        var request = urlRequest
        // 判断当前网络是否可用,可直接使用Alamofire自带的网络状态监听能力
        if !(NetworkReachabilityManager.default?.isReachable ?? false) {
            // 离线状态下直接返回缓存,不校验有效期
            request.cachePolicy = .returnCacheDataDontLoad
        } else {
            // 在线状态下遵守协议缓存策略,自动判断缓存是否超过2小时有效期
            request.cachePolicy = .useProtocolCachePolicy
        }
        completion(.success(request))
    }
}

// 初始化会话时传入拦截器
let aSession = Session(
    configuration: sessionConfiguration,
    interceptor: CacheInterceptor(),
    cachedResponseHandler: responseCacher
)
注意事项
  • 仅GET请求会被系统默认缓存,POST等其他请求需要额外处理缓存逻辑
  • 首次请求成功后响应才会写入缓存,后续请求才会命中缓存
  • 确保URLCache容量足够,超出容量的缓存会被系统自动清理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 01:21:02