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

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与服务器通信,避免了协议协商的冲突;
  • 移除Upgrade header消除了服务器无法识别的协议字段,避免触发错误;
  • 修复请求体构建保证了数据的完整性和长度的准确性,服务器能正确解析请求并返回响应。

把这三个方案结合起来,就能彻底解决你遇到的周期性协议错误问题。

内容的提问来源于stack exchange,提问作者J.K Jeon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 17:12:56