Build robust and resumable file transfers
System & Services 进阶 20m

构建健壮且可恢复的文件传输

Build robust and resumable file transfers

2023年6月5日

在 Apple 官方观看视频

一句话判断

iOS 17 终于支持可恢复的上传任务了,下载和上传现在都能从中断处继续——这对大文件传输是改变游戏规则的更新。

这场 Session 讲了什么

URLSession 在 iOS 17 中引入了可恢复上传任务(Resumable Upload Tasks),与已有的可恢复下载功能形成完整的文件传输方案。

可恢复下载使用 HTTP Range 请求。客户端发送 GET 请求后,服务器通过 Accept-Ranges 头声明支持范围请求,并通过 ETag 标识资源版本。中断后,客户端发送 Range 请求获取缺失部分,附带 If-Range 头验证资源未变化。URLSession 的 cancelByProducingResumeData 方法暂停下载并返回恢复数据,downloadTask(withResumeData:) 从恢复点继续。

可恢复上传使用最新的 IETF 标准草案协议。API 与下载完全一致:cancelByProducingResumeData 暂停,uploadTask(withResumeData:) 恢复。如果只是短暂中断但服务器可达,URLSession 会自动恢复上传。

Session 还讲解了 Background URLSession 如何优雅处理用户和网络中断。

值得深挖的点

可恢复上传的协议细节值得了解。与下载的 Range 请求不同,上传使用的是全新的 IETF 标准草案。目前该协议正在 IETF 进行跨行业的标准化工作。

自动恢复与手动恢复的区分很重要。短暂的网络波动但服务器仍可达时,URLSession 自动重试。但如果是更广泛的连接问题(如网络或服务器完全宕机),你需要在错误中检查恢复数据,就像下载任务一样。

代码片段

// 可恢复下载
let downloadTask = session.downloadTask(with: url)
downloadTask.resume()

// 暂停下载
downloadTask.cancelByProducingResumeData { resumeData in
    self.savedResumeData = resumeData
}

// 恢复下载
let resumedTask = session.downloadTask(withResumeData: savedResumeData)
resumedTask.resume()

// 从错误中恢复下载
func urlSession(_:task:didCompleteWithError error: Error?) {
    if let error = error,
       let resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData] 
                        as? Data {
        // 保存恢复数据,稍后继续
        self.savedResumeData = resumeData
    }
}

// 可恢复上传(iOS 17 新增)
let uploadTask = session.uploadTask(with: request, from: fileData)
uploadTask.resume()

// 暂停和恢复上传(与下载 API 一致)
uploadTask.cancelByProducingResumeData { resumeData in
    self.savedUploadResumeData = resumeData
}
let resumedUpload = session.uploadTask(withResumeData: savedUploadResumeData)
resumedUpload.resume()

最佳实践

  • 服务器必须支持最新的可恢复上传协议草案
  • 使用 cancelByProducingResumeData 而非 cancel() 以保留恢复能力
  • 从错误中提取恢复数据处理意外中断
  • 上传自动恢复只在服务器可达时生效
  • Background URLSession 适合长时间运行的传输任务

还有什么值得关注

  • 可恢复下载要求服务器返回 Accept-Ranges 和 ETag
  • 临时下载文件可能因磁盘空间压力被系统删除
  • SwiftNIO 可以用来为服务器添加可恢复上传支持
  • 参考 Background URLSession 相关文档了解后台传输
WWDC 2023