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

SwiftUI中发起HTTP多部分表单数据请求时出现异常错误

Swift multipart/form-data 文件上传错误排查与修复

我用以下Swift代码实现POST请求+form-data格式上传文件:

let contentType = "multipart/form-data; boundary=\(boundary)"
urlRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")

let fileName:String = String(request.fileURLForFormData!.path().split(separator: "/").last ?? "")
let fileData = try Data(contentsOf: request.fileURLForFormData!)
var uploadData = Data()

// Append file data
uploadData.append("--\(boundary)\r\n".data(using: .utf8)!)
uploadData.append("Content-Disposition: form-data; name=\"image\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!)
uploadData.append("Content-Type: \(fileName.mimeType())\r\n\r\n".data(using: .utf8)!)
uploadData.append(fileData)
uploadData.append("\r\n".data(using: .utf8)!)

// Close the form data
uploadData.append("--\(boundary)--\r\n".data(using: .utf8)!)

// Set the request body
urlRequest.httpBody = uploadData
let (data, response) = try await URLSession.shared.upload(for: urlRequest, from: Data(contentsOf: request.fileURLForFormData!))

return .success((data, response))

运行时触发错误:

上传任务的请求不应包含请求体或请求体流,请使用upload(for:fromFile:)、upload(for:from:),或通过urlSession(_:needNewBodyStreamForTask:)代理方法提供请求体流。


错误核心原因

你同时执行了两个冲突操作:给urlRequest设置了httpBody,又调用了URLSession的upload(for:from:)方法。upload系列方法的设计逻辑是自行负责构建请求体,不允许提前给请求对象设置httpBody,否则就会触发该报错。


两种修复方案

方案1:改用data方法发送(适合已手动组装好form-data的场景)

既然已经手动构建了完整的multipart/form-data请求体,直接用data系列方法发送即可,无需调用upload:

let contentType = "multipart/form-data; boundary=\(boundary)"
urlRequest.setValue(contentType, forHTTPHeaderField: "Content-Type")
urlRequest.httpMethod = "POST" // 确保设置POST请求方法

let fileName:String = String(request.fileURLForFormData!.path().split(separator: "/").last ?? "")
let fileData = try Data(contentsOf: request.fileURLForFormData!)
var uploadData = Data()

// Append file data
uploadData.append("--\(boundary)\r\n".data(using: .utf8)!)
uploadData.append("Content-Disposition: form-data; name=\"image\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!)
uploadData.append("Content-Type: \(fileName.mimeType())\r\n\r\n".data(using: .utf8)!)
uploadData.append(fileData)
uploadData.append("\r\n".data(using: .utf8)!)

// Close the form data
uploadData.append("--\(boundary)--\r\n".data(using: .utf8)!)

// Set the request body
urlRequest.httpBody = uploadData
// 改用data方法发送请求
let (data, response) = try await URLSession.shared.data(for: urlRequest)

return .success((data, response))

方案2:使用upload方法(适合直接上传文件的场景)

如果后端支持直接接收文件流,无需手动构建form-data,可以去掉httpBody设置,用upload(for:fromFile:)更高效(避免把大文件读入内存):

// 注意:使用upload方法时,不要设置urlRequest.httpBody
urlRequest.httpMethod = "POST"
// 根据文件类型设置Content-Type
let mimeType = request.fileURLForFormData!.path().mimeType()
urlRequest.setValue(mimeType, forHTTPHeaderField: "Content-Type")

// 直接传入文件URL,无需读入内存
let (data, response) = try await URLSession.shared.upload(for: urlRequest, fromFile: request.fileURLForFormData!)

return .success((data, response))

内容的提问来源于stack exchange,提问作者sumit kumar Pradhan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 14:47:39