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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 02:33:09