为什么 URLSession 上传任务取消后返回 nil resumeData?
数据阿明
结论
URLSessionUploadTask 支持通过 cancelByProducingResumeData() 暂停上传并尝试续传,所以返回 nil 不代表上传任务不支持这个 API。Apple 文档指出,如果服务器不支持当前的 resumable uploads Internet-Draft,返回的 resumeData 就会是 nil。收到 104 Upload Resumption Supported 表示 delegate 收到了 informational response,但仅凭这一点无法确认服务器和 URLSession 的续传协议实现兼容。Apple:暂停和恢复上传;Apple:cancel(byProducingResumeData:)
先确认日志和示例是否对应同一次请求
问题中的客户端代码设置了 Upload-Incomplete: ?0 和 Upload-Draft-Interop-Version: 3,但日志记录的是 Upload-Complete: ?1、Upload-Draft-Interop-Version: 6,还包含 Upload-Length。这些值并不一致,说明运行的代码、请求构造方式或日志可能来自不同版本。排查时,先记录实际发出的请求头和服务器返回的完整 104 响应头,确认它们对应同一次上传。
建议的排查步骤
- 核对服务器实现是否兼容客户端要求的草案版本。 Apple 将返回
nil与服务器不支持当前的 resumable uploads Internet-Draft 联系起来。除了检查服务器是否返回状态码104,还要根据 Apple 文档和当前采用的草案核对完整的协议交互。 - 检查
104响应的完整内容。 日志显示响应中包含Location。请确认它是这次上传对应的有效续传地址,并核对其他响应头是否符合所实现的协议版本。现有日志不足以判断响应是否完整或符合要求。 - 对照同一次请求的收发记录。 将客户端发送的请求头、服务器收到的请求头、服务器发出的 informational response 及其头字段放在一起检查。重点确认请求方法、上传状态相关头字段和草案版本没有被代码或服务器改写。
- 检查返回值,只在非
nil时保存续传数据。 Apple 的示例也要求检查返回值,因为取消任务时不一定能生成可用的续传数据。
let resumeData = await uploadTask.cancelByProducingResumeData()
if let resumeData {
// 保存 resumeData,后续用于创建续传任务
} else {
// 本次上传没有生成可用的续传数据
}
拿到有效数据后,可以使用 URLSession 的 uploadTask(withResumeData:) 创建续传任务。手动暂停和续传适用于非后台 session;后台配置会自动处理上传恢复。Apple:暂停和恢复上传
现有信息不足以确定是哪个请求头或服务器行为导致了 nil。先确认日志和示例请求是否一致,再根据实际收发数据核对草案兼容性。
备注:内容仅供参考。
