Swift实现iOS多文件上传时大文件上传后仅1KB问题求助
问题核心原因
- 二进制文件错误使用UTF8编码转字符串:WAV音频属于二进制格式,不属于UTF8文本内容,
String(data: fileData, encoding: .utf8)执行后直接返回nil,导致最终拼接的请求体里没有实际的文件二进制内容,只有请求头信息,所以上传后文件只有1KB大小。 - multipart请求体构造逻辑错误:multipart/form-data包含二进制内容时,全程用字符串拼接会丢失二进制数据,应该直接用
Data类型构造请求体。
其他错误点
- 音频文件的Content-Type写死为无效值
"content-type header",正确值应为audio/wav - 在主线程使用
DispatchSemaphore.wait()会阻塞主线程,可能导致界面无响应甚至被系统强杀,不需要用信号量同步异步请求,直接在请求回调里处理后续逻辑即可 - 文件名拼接时额外加了
file:///前缀,服务端接收文件名时会出现冗余前缀
修复后代码
func uploadFile(){ var parameters: [[String: Any]] = [] var fileCount: Int = 0 let homeDirectory = "" var soundPath = "\(homeDirectory)\(CommonUtil.PATH_SOUND)" soundPath = soundPath.replacingOccurrences(of: "file:///", with: "") for item in files{ guard let dict = item as? [String:String], let fileName = dict["fileName"] else { continue } let strFilePath = "\(soundPath)\(fileName)" if FileManager.default.fileExists(atPath: strFilePath){ var paramDict = [String:Any]() paramDict.updateValue("strFileName[\(fileCount)]", forKey: "key") paramDict.updateValue(strFilePath, forKey: "src") paramDict.updateValue("file", forKey: "type") paramDict.updateValue("audio/wav", forKey: "contentType") parameters.append(paramDict) fileCount += 1 } print(fileName) } var dict = [String:Any]() dict.updateValue("strApiName", forKey: "key") dict.updateValue("soundFileUpload", forKey: "value") dict.updateValue("text", forKey: "type") parameters.append(dict) uploadFiles(parameters: parameters) } func uploadFiles(parameters: [[String: Any]]){ showLoading(show: true) let boundary = "Boundary-\(UUID().uuidString)" var body = Data() for param in parameters { guard param["disabled"] == nil, let paramName = param["key"] as? String else { continue } // 拼接边界 body.append("--\(boundary)\r\n".data(using: .utf8)!) // 拼接Content-Disposition var disposition = "Content-Disposition:form-data; name=\"\(paramName)\"" let paramType = param["type"] as? String ?? "text" if paramType == "file", let fileName = (param["src"] as? NSString)?.lastPathComponent { disposition += "; filename=\"\(fileName)\"\r\n" } else { disposition += "\r\n" } body.append(disposition.data(using: .utf8)!) // 拼接Content-Type if let contentType = param["contentType"] as? String { body.append("Content-Type: \(contentType)\r\n".data(using: .utf8)!) } // 空行分隔头和内容 body.append("\r\n".data(using: .utf8)!) // 拼接内容 if paramType == "text", let paramValue = param["value"] as? String { body.append("\(paramValue)\r\n".data(using: .utf8)!) } else if paramType == "file", let paramSrc = param["src"] as? String, let fileData = try? Data(contentsOf: URL(fileURLWithPath: paramSrc)) { body.append(fileData) body.append("\r\n".data(using: .utf8)!) } } // 拼接结束边界 body.append("--\(boundary)--\r\n".data(using: .utf8)!) var request = URLRequest(url: URL(string: "http://api.polytus.com/")!,timeoutInterval: 30) request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" request.httpBody = body let task = URLSession.shared.dataTask(with: request) { data, response, error in DispatchQueue.main.async { self.showLoading(show: false) if let error = error { print(error) self.showBluetoothAlert(message: "failed") return } guard let data = data, let respStr = String(data: data, encoding: .utf8) else { self.showBluetoothAlert(message: "failed") return } print(respStr) self.showBluetoothAlert(message: "success") } } task.resume() }
内容的提问来源于stack exchange,提问作者Akmal Bukhariev
相关产品推荐
相关产品推荐

