SwiftUI+Directus图片上传问题:UIImage无法正确转换发送请求
解决UIImage上传服务器的JSON无效与图片转换问题
错误原因
- JSON序列化不支持Data类型:直接将
UIImage转换后的Data对象放入JSON字典中,JSONSerialization无法序列化原生Data类型,这是抛出Invalid type in JSON write (Foundation.__NSSwiftData)异常的核心原因。 - 请求格式不匹配:设置了
Content-Type为multipart/form-data,但实际用JSON格式构建请求体,不符合multipart请求的规范。
解决方案一:将图片转为Base64字符串嵌入JSON(适合小图片)
如果服务器支持接收Base64编码的图片,可以把Data转成Base64字符串后放入JSON:
@MainActor private func postImage(token: Token, title: String, picture: UIImage) async { guard let urlRegister = URL(string: "https://serveurexemple/files") else { return } guard let pictureData = picture.jpegData(compressionQuality: 0.8) else { print("图片转换失败") return } let base64Image = pictureData.base64EncodedString() var request = URLRequest(url: urlRegister) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.addValue("Bearer \(token.access_token)", forHTTPHeaderField: "Authorization") let jsonObject: [String: Any] = ["title": title, "files": base64Image] do { let jsonData = try JSONSerialization.data(withJSONObject: jsonObject) request.httpBody = jsonData let (_, response) = try await URLSession.shared.data(for: request) if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode != 200 { print("请求失败,状态码:\(httpResponse.statusCode)") } } catch { print("JSON序列化或请求错误:\(error.localizedDescription)") } }
注意:Base64编码会让数据体积增大约30%,大图片不建议使用这种方式。
解决方案二:构建标准multipart/form-data请求(推荐)
这是HTTP文件上传的标准方式,更适合传输图片文件,数据体积更小,服务器端处理更便捷:
@MainActor private func postImage(token: Token, title: String, picture: UIImage) async { guard let urlRegister = URL(string: "https://serveurexemple/files") else { return } guard let pictureData = picture.jpegData(compressionQuality: 0.8) else { print("图片转换失败") return } let boundary = UUID().uuidString var request = URLRequest(url: urlRegister) request.httpMethod = "POST" request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type") request.addValue("Bearer \(token.access_token)", forHTTPHeaderField: "Authorization") var body = Data() // 添加title字段 body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"title\"\r\n\r\n".data(using: .utf8)!) body.append("\(title)\r\n".data(using: .utf8)!) // 添加图片文件 body.append("--\(boundary)\r\n".data(using: .utf8)!) body.append("Content-Disposition: form-data; name=\"files\"; filename=\"image.jpg\"\r\n".data(using: .utf8)!) body.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!) body.append(pictureData) body.append("\r\n".data(using: .utf8)!) // 结束边界 body.append("--\(boundary)--\r\n".data(using: .utf8)!) request.httpBody = body do { let (_, response) = try await URLSession.shared.data(for: request) if let httpResponse = response as? HTTPURLResponse { print("请求状态码:\(httpResponse.statusCode)") } } catch { print("请求错误:\(error.localizedDescription)") } }
内容的提问来源于stack exchange,提问作者Rémy Martenon
相关产品推荐
相关产品推荐

