URLSession默认缓存策略下未捕获304状态码问题咨询
获取URLSession真实的304状态码
默认情况下,URLSession的completion handler会自动封装304响应逻辑——把服务器返回的304状态码替换成200,同时直接返回本地缓存的数据,这是Foundation框架为简化开发者流程做的封装。如果要拿到真实的304状态码,你需要切换到代理模式处理请求,而非使用便捷的completion handler方法。
具体实现步骤如下:
实现
URLSessionDataDelegate协议
你需要实现协议里的几个关键方法,用来捕获原始响应、处理数据接收以及请求完成后的逻辑。创建带代理的URLSession实例
保持默认的useProtocolCachePolicy(这也是URLSessionConfiguration的默认策略,可省略显式设置),初始化绑定代理的Session:let sessionConfig = URLSessionConfiguration.default let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: OperationQueue.main)在代理方法中捕获真实状态码
在didReceiveResponse方法里,你能直接拿到服务器返回的原始HTTP响应,包括304状态码:func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { guard let httpResponse = response as? HTTPURLResponse else { completionHandler(.allow) return } // 这里就能拿到真实的状态码了 let realStatusCode = httpResponse.statusCode print("服务器返回的真实状态码: \(realStatusCode)") if realStatusCode == 304 { // 304表示缓存有效,需要自行从URLCache读取缓存数据 if let cachedResponse = session.configuration.urlCache?.cachedResponse(for: dataTask.currentRequest!) { // 处理缓存的cachedResponse.data print("使用本地缓存数据") } // 304没有响应体,直接取消数据接收即可 completionHandler(.cancel) } else { // 其他状态码正常处理,允许接收响应数据 completionHandler(.allow) } }处理非304场景的数据接收
实现didReceive data方法来收集正常响应的数据:var receivedData = Data() func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { receivedData.append(data) }处理请求完成逻辑
在didCompleteWithError方法里完成后续的结果处理:func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { if let error = error { print("请求出错: \(error.localizedDescription)") return } // 在这里处理receivedData(非304场景)或缓存的数据(304场景) }
关键提示
- 代理模式下Foundation不会自动处理304到200的转换,你能完全掌控原始响应状态。
- 收到304时服务器不会返回响应体,必须自行从
URLCache读取对应的缓存内容。 - URLSession会自动在有缓存的请求中添加
Etag和If-None-Match头,无需手动处理。
内容的提问来源于stack exchange,提问作者Chamitha
相关产品推荐
相关产品推荐

