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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:54:04