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

iOS 16中URLSessionUploadTask上传陷入无限循环问题排查

问题分析与解决方案

核心循环诱因

  • 认证挑战时序冲突+请求体重复发送:服务器先触发SSL信任挑战,客户端处理后发送请求体,随后服务器返回HTTP Basic认证要求——URLSession会重新发起完整请求流程,包括重发请求体。你的请求体是字符串构造的multipart数据,可能在重发时出现字节数翻倍(比如字符串拼接逻辑重复),再加上认证凭证未被正确缓存,导致循环触发。
  • 请求体格式无效:用字符串而非真实二进制zip数据构造multipart请求,服务器无法解析请求,返回异常响应(比如误判认证状态),触发客户端重试逻辑。

分步修复方案

1. 修复HTTP Basic认证凭证缓存逻辑

使用带代理的URLSession实例,确保处理认证挑战时正确缓存凭证,避免重复触发认证:

func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge) async -> (URLSession.AuthChallengeDisposition, URLCredential?) {
    // 处理HTTP Basic认证
    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic {
        let credential = URLCredential(user: "你的用户名", password: "你的密码", persistence: .permanent)
        return (.useCredential, credential)
    }
    // 处理服务器信任挑战(针对自签名证书场景)
    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
        guard let serverTrust = challenge.protectionSpace.serverTrust else {
            return (.performDefaultHandling, nil)
        }
        let credential = URLCredential(trust: serverTrust)
        return (.useCredential, credential)
    }
    return (.performDefaultHandling, nil)
}

注意:不要使用URLSession.shared,需手动初始化带代理的URLSession实例,才能正确复用缓存的认证凭证。

2. 重构请求体为二进制格式

替换字符串构造multipart请求的逻辑,直接用Data拼接真实二进制zip数据,避免编码或重复拼接导致的字节异常:

func buildValidMultipartData(boundary: String, zipData: Data, fileName: String) -> Data {
    let formData = NSMutableData()
    // 添加表单边界与字段描述
    formData.append("--\(boundary)\r\n".data(using: .utf8)!)
    formData.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!)
    formData.append("Content-Type: application/zip\r\n\r\n".data(using: .utf8)!)
    // 追加真实二进制zip数据
    formData.append(zipData)
    // 闭合表单边界
    formData.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)
    return formData as Data
}

3. 禁用URLSession自动重试(可选)

若服务器端认证时序存在问题,可通过配置禁用自动重试,避免循环触发:

let sessionConfig = URLSessionConfiguration.default
sessionConfig.httpMaximumConnectionsPerHost = 1
sessionConfig.timeoutIntervalForRequest = 30
// 禁用自动重试逻辑
sessionConfig.shouldUseExtendedBackgroundIdleMode = false
let customSession = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)

额外排查建议

  • 抓包验证请求:用Charles或Wireshark抓取请求,确认每次循环的请求头、请求体是否重复,服务器返回的状态码(比如是否重复返回401未授权)。
  • 检查服务器日志:确认服务器是否收到请求体,是否因格式错误返回异常状态码触发客户端重试。

内容的提问来源于stack exchange,提问作者Fritz Anderson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:35:21