Swift 5.7多表单数据图片上传异常:3张图请求无响应
Swift 5.7多图上传请求失败排查与解决建议
我在Swift 5.7环境下,尝试通过multipart/form-data请求向服务器发送3张图片及其他附加数据,但仅移除后两张图片时,请求才能正常触达服务器。以下是相关代码片段,寻求问题排查方向,实现3张图片同请求上传。
相关代码
Service.swift
let networker = Networker() let serverUrl = URL(string: "https://myurl.com") var urlRequest = URLRequest(url: serverUrl!) let boundary = UUID().uuidString urlRequest.httpMethod = "POST" urlRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") let requestData = networker.buildMultipartImageRequest(boundary: boundary, item: items) URLSession.shared.uploadTask(with: urlRequest, from: requestData) {(data, response, error) in // 处理响应 }.resume()
Networker.swift
func buildMultipartImageRequest(boundary: String, item: ItemForBackend, itemId:UInt = 0) -> Data { var data = Data() // 添加上传图片数据 data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) data.append("Content-Disposition: form-data; name=\"images\"; filename=\"\(item.filename1)\"\r\n".data(using: .utf8)!) data.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!) data.append(item.image1) // 取消注释这两段后,请求完全无法发送! // data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) // data.append("Content-Disposition: form-data; name=\"images\"; filename=\"\(item.filename2)\"\r\n".data(using: .utf8)!) // data.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!) // data.append(item.image2) // // data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) // data.append("Content-Disposition: form-data; name=\"images\"; filename=\"\(item.filename3)\"\r\n".data(using: .utf8)!) // data.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!) // data.append(item.image3) // 添加附加参数 let paramObj:[String: Any] = item.getParams() for(key, value) in paramObj { data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) data.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!) data.append("\(value)\r\n".data(using: .utf8)!) } if itemId != 0 { data.append("\r\n--\(boundary)\r\n".data(using: .utf8)!) data.append("Content-Disposition: form-data; name=\"itemId\"\r\n\r\n".data(using: .utf8)!) data.append("\(itemId)\r\n".data(using: .utf8)!) } data.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!) return data }
排查方向与解决建议
- 检查请求数据大小限制:三张图片总大小可能超过服务器配置的最大请求体限制(比如Nginx的
client_max_body_size),或者触发了客户端内存预警。可以打印requestData.count对比单图和三图时的数据量,同时联系后端确认服务器的大小限制。 - 修正multipart字段命名格式:部分后端框架(如PHP)要求多文件字段名带
[]后缀才能识别,把图片字段的name=\"images\"改成name=\"images[]\"试试。 - 验证图片数据有效性:检查
image2和image3是否为完整有效的JPEG数据,打印它们的字节数确认数据长度合理,避免空数据或损坏数据导致请求格式错误。 - 改用OutputStream构建请求数据:手动拼接大
Data容易出现内存溢出或隐式拼接错误,用OutputStream流式构建数据更稳定,示例代码如下:
func buildMultipartImageRequest(boundary: String, item: ItemForBackend, itemId: UInt = 0) -> Data { let outputStream = OutputStream(toMemory: ()) outputStream.open() func write(_ string: String) { if let data = string.data(using: .utf8) { data.withUnsafeBytes { buffer in outputStream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: data.count) } } } // 第一张图 write("\r\n--\(boundary)\r\n") write("Content-Disposition: form-data; name=\"images[]\"; filename=\"\(item.filename1)\"\r\n") write("Content-Type: image/jpeg\r\n\r\n") item.image1.withUnsafeBytes { buffer in outputStream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: item.image1.count) } // 第二张图 write("\r\n--\(boundary)\r\n") write("Content-Disposition: form-data; name=\"images[]\"; filename=\"\(item.filename2)\"\r\n") write("Content-Type: image/jpeg\r\n\r\n") item.image2.withUnsafeBytes { buffer in outputStream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: item.image2.count) } // 第三张图 write("\r\n--\(boundary)\r\n") write("Content-Disposition: form-data; name=\"images[]\"; filename=\"\(item.filename3)\"\r\n") write("Content-Type: image/jpeg\r\n\r\n") item.image3.withUnsafeBytes { buffer in outputStream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: item.image3.count) } // 附加参数 let paramObj = item.getParams() for (key, value) in paramObj { write("\r\n--\(boundary)\r\n") write("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n") write("\(value)\r\n") } if itemId != 0 { write("\r\n--\(boundary)\r\n") write("Content-Disposition: form-data; name=\"itemId\"\r\n\r\n") write("\(itemId)\r\n") } write("\r\n--\(boundary)--\r\n") outputStream.close() return outputStream.property(forKey: .dataWrittenToMemoryStreamKey) as! Data }
- 更换URLSession上传方式:尝试用
dataTask(with:request, completionHandler:)替代uploadTask,同时打印error信息,确认请求失败的具体原因。 - 确认服务器端接收逻辑:联系后端开发人员,确认服务器是否支持接收多个同名字段的文件,是否需要调整后端的文件接收配置。
内容的提问来源于stack exchange,提问作者Tank12
相关产品推荐
相关产品推荐

