使用Alamofire下载文件遇-1001错误:等待服务器文件同步方案咨询
解决Alamofire下载PDF时服务器后台拉取文件导致的空文件与-100系列错误问题
我来帮你搞定这个问题!你遇到的情况本质是服务器的“懒加载”文件分发逻辑和Alamofire默认的请求策略不兼容——服务器需要先从其他节点拉取文件,这个过程需要时间,但Alamofire默认的超时设置太短,导致请求提前中断,最后拿到空文件,同时触发-100系列错误(比如-1001超时、-1005连接断开)。下面是几个针对性的解决方案,你可以根据服务器的实际情况组合使用:
1. 延长请求超时时间,给服务器足够的文件准备时间
服务器从其他节点下载文件可能需要几十秒甚至几分钟,Alamofire默认的超时时间(一般是60秒)根本不够。你可以通过自定义Session配置来延长超时:
// 创建自定义Session配置 let configuration = URLSessionConfiguration.default // 设置单次请求超时时间(比如5分钟) configuration.timeoutIntervalForRequest = 300 // 设置整个资源下载的超时时间(比如10分钟) configuration.timeoutIntervalForResource = 600 // 使用配置创建Alamofire Session let session = AF.Session(configuration: configuration) // 用这个session发起下载请求 session.download(downloadURL) .destination { _, _ in // 指定本地保存路径 let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] return (documentsDir.appendingPathComponent("target.pdf"), .removePreviousFile) } .response { response in switch response.result { case .success(let url): print("文件下载完成,路径:\(url)") // 这里可以检查文件大小,避免空文件 if let fileSize = try? FileManager.default.attributesOfItem(atPath: url.path)[.size] as? Int64, fileSize > 0 { // 文件有效,处理逻辑 } else { print("下载的文件为空") } case .failure(let error): print("下载失败:\(error)") } }
2. 实现轮询机制(如果服务器支持返回202状态码)
很多这类服务器在文件准备中会返回202 Accepted状态码,同时可能在响应头里提示重试间隔。这种情况下,你可以写一个轮询逻辑,直到服务器返回200 OK和文件内容:
func pollForFileDownload(url: URL, retryInterval: TimeInterval = 10, maxRetries: Int = 10) { guard maxRetries > 0 else { print("重试次数耗尽,下载失败") return } AF.download(url) .validate(statusCode: 200..<300) .response { response in if let error = response.error { // 检查是否是202状态码导致的验证失败 if let statusCode = response.response?.statusCode, statusCode == 202 { print("文件正在准备中,\(retryInterval)秒后重试...") DispatchQueue.main.asyncAfter(deadline: .now() + retryInterval) { self.pollForFileDownload(url: url, retryInterval: retryInterval, maxRetries: maxRetries - 1) } } else { print("下载出错:\(error)") } } else if let fileURL = response.fileURL { print("文件下载完成:\(fileURL)") // 处理文件逻辑 } } } // 调用轮询函数 pollForFileDownload(url: downloadURL)
3. 配置自动重试策略,针对-100系列错误
对于-100系列的超时/连接错误,你可以通过Alamofire的RequestRetrier协议实现自动重试:
class DownloadRetryRetrier: RequestRetrier { func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) { // 判断是否是-100系列错误 if let afError = error as? AFError, let urlError = afError.underlyingError as? URLError, [URLError.timedOut, URLError.networkConnectionLost].contains(urlError.code) { // 最多重试3次,每次间隔5秒 if request.retryCount < 3 { completion(.retryWithDelay(5)) } else { completion(.doNotRetry) } } else { completion(.doNotRetry) } } } // 创建带重试策略的Session let retryRetrier = DownloadRetryRetrier() let session = AF.Session(configuration: .default, retrier: retryRetrier) // 使用这个session发起下载 session.download(downloadURL) .destination { _, _ in let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] return (documentsDir.appendingPathComponent("target.pdf"), .removePreviousFile) } .response { response in // 处理结果 }
4. 额外检查:确保下载完成后的文件有效性
不管用哪种方法,最后都要检查下载后的文件大小是否大于0,避免拿到空文件:
func validateDownloadedFile(at url: URL) -> Bool { guard FileManager.default.fileExists(atPath: url.path) else { return false } do { let attributes = try FileManager.default.attributesOfItem(atPath: url.path) if let fileSize = attributes[.size] as? Int64, fileSize > 0 { return true } } catch { print("检查文件大小出错:\(error)") } return false }
总结建议
- 优先尝试延长超时时间,这是最简单直接的方法;
- 如果服务器返回202状态码,结合轮询机制会更高效;
- 加上自动重试策略可以应对偶尔的网络波动导致的-100错误;
- 最后一定要做文件有效性检查,确保拿到的不是空文件。
内容的提问来源于stack exchange,提问作者gregkyt
相关产品推荐
相关产品推荐

