URLSession缓存未按官方文档预期工作 排查与方案咨询
根据官方文档说明,使用默认useProtocolCachePolicy缓存策略时,逻辑应如下:
- 若请求无对应缓存响应,URL加载系统会从源站拉取数据;
- 若存在缓存响应,且缓存未标注每次请求都需重新校验、同时缓存未过期(未超出有效期),URL加载系统直接返回缓存响应;
- 若缓存已过期或需要重新校验,URL加载系统会向源站发送
HEAD请求确认资源是否变更:若资源已变更则从源站拉取新数据,未变更则返回本地缓存响应。
但实际测试结果与文档描述完全不符:即使响应已缓存也从未被使用,系统也从未发送过HEAD请求。
测试请求的目标URL会返回固定不变的ETag与Last-Modified响应头,且已至少发起过一次请求,确认响应已完成缓存(可通过iOS模拟器中应用的缓存数据库验证)。
使用默认useProtocolCachePolicy策略
若初始化URLSession时所用URLSessionConfiguration的requestCachePolicy设为useProtocolCachePolicy,响应确实会被存入缓存(可在缓存DB中查到),但缓存从未被调用:重复请求同URL时始终会发起新的GET请求,且不会携带If-None-Match或If-Modified-Since请求头,服务器始终返回HTTP 200全量响应,本地缓存被完全忽略。
为每个URLRequest单独设置reloadRevalidatingCacheData策略
若为每一个URLRequest单独设置cachePolicy为reloadRevalidatingCacheData,缓存机制可正常生效:每次发起请求时,GET请求会携带If-None-Match(值为缓存响应的ETag)与If-Modified-Since(值为缓存响应的Last-Modified)请求头;因资源未变更,服务器返回304 Not Modified,系统将本地缓存响应返回给调用方。
仅在URLSessionConfiguration上设置reloadRevalidatingCacheData策略
若仅在URLSessionConfiguration上设置requestCachePolicy = .reloadRevalidatingCacheData(而非为每个URLRequest单独设置),应用启动后仅首次请求会携带缓存相关请求头并收到304 Not Modified响应,后续请求均为无缓存头的普通GET请求。
测试结论
其余缓存策略均为“仅使用缓存数据”或“完全不使用缓存”的变体,与本次测试场景无关。
测试中完全不存在URLSession如文档描述那样发送HEAD请求的场景,也从未出现过基于原响应的过期时间信息直接返回缓存、无需重校验的情况。
目前采用的临时方案是为每一个URLRequest设置cachePolicy = .reloadRevalidatingCacheData,以实现基础的本地缓存能力:因为304 Not Modified响应仅返回响应头、不返回响应体,可减少网络传输流量。
希望了解是否存在更优解决方案,或如何配置才能让URLSession按照官方文档描述的逻辑正常工作。
内容的提问来源于stack exchange,提问作者mluisbrown

