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
相关产品推荐
相关产品推荐

