Swift中URLSession调用HTTPS服务器遇无效HTTP头错误求助
解决URLSession与Apache HTTP/1.1服务器通信时的HTTP/2协议错误
从你给出的错误信息和代码来看,问题的核心是URLSession默认尝试与服务器协商HTTP/2协议,但你的Apache服务器仅支持HTTP/1.1,同时请求的multipart/form-data构建存在编码问题,两者共同导致了周期性的协议错误。下面是具体的解决方案:
1. 强制URLSession使用HTTP/1.1,禁用HTTP/2支持
URLSession在HTTPS环境下默认会尝试协商HTTP/2,如果服务器不支持该协议,就会出现Upgrade: h2,h2c的header冲突错误。你可以通过自定义会话配置来强制使用HTTP/1.1:
// 创建自定义会话配置,禁用HTTP/2 let config = URLSessionConfiguration.default config.httpVersion = .http1_1 config.httpMaximumConnectionsPerHost = 1 config.httpShouldUsePipelining = false // 使用自定义配置创建URLSession,替代默认的shared会话 let session = URLSession(configuration: config) // 用这个session发起请求 self.task = session.dataTask(with: request as URLRequest, completionHandler: { [weak self] (data, response, error) -> Void in // 你的响应处理逻辑 })
2. 移除请求中的Upgrade header
错误日志明确提到收到了Upgrade: h2,h2c的非法header,这是HTTP/2协商的触发字段。如果你的headerValues中包含这个字段,直接过滤掉:
for (key, value) in self.headerValues ?? [:] { // 跳过Upgrade header,避免触发HTTP/2协商 if key.lowercased() == "upgrade" { continue } if request.value(forHTTPHeaderField: key) != nil { continue } request.addValue(value, forHTTPHeaderField: key) }
3. 修复multipart/form-data的请求体构建问题
你的代码中处理图片附件时,将二进制数据转为UTF-8字符串是严重错误的——图片是二进制格式,UTF-8编码会损坏数据,导致请求体长度计算不准确,服务器无法正确解析请求,进而不返回响应。改用Data直接构建请求体:
var bodyData = Data() let boundary = kBoundaryString // 添加普通参数 for (key, value) in self.parameters?.dict ?? [:] { bodyData.append("--\(boundary)\r\n".data(using: .utf8)!) bodyData.append("Content-Disposition:form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!) // 处理数组类型参数(用JSON序列化) if let valueArray = value as? [Any], let valueData = try? JSONSerialization.data(withJSONObject: valueArray) { bodyData.append(valueData) } // 处理字符串类型参数 else if let valueString = value as? String { bodyData.append(valueString.data(using: .utf8)!) } // 其他类型转为字符串 else { bodyData.append("\(value)".data(using: .utf8)!) } bodyData.append("\r\n".data(using: .utf8)!) } // 添加图片附件 for attachment in attachments ?? [] { bodyData.append("--\(boundary)\r\n".data(using: .utf8)!) bodyData.append("Content-Disposition:form-data; name=\"\(attachment.key)\"; filename=\"\(attachment.fileName)\"\r\n".data(using: .utf8)!) if attachment.type == .Image { // 设置正确的图片Content-Type,比如image/jpeg或image/png bodyData.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!) // 直接添加二进制图片数据,无需转字符串 bodyData.append(attachment.data) } bodyData.append("\r\n".data(using: .utf8)!) } // 结束边界 bodyData.append("--\(boundary)--\r\n".data(using: .utf8)!) // 设置请求体和正确的Content-Length request.httpBody = bodyData request.setValue("\(bodyData.count)", forHTTPHeaderField: "Content-Length")
为什么这些方案有效?
- 禁用HTTP/2后,URLSession会直接使用HTTP/1.1与服务器通信,避免了协议协商的冲突;
- 移除
Upgradeheader消除了服务器无法识别的协议字段,避免触发错误; - 修复请求体构建保证了数据的完整性和长度的准确性,服务器能正确解析请求并返回响应。
把这三个方案结合起来,就能彻底解决你遇到的周期性协议错误问题。
内容的提问来源于stack exchange,提问作者J.K Jeon
相关产品推荐
相关产品推荐

