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

SwiftUI+Directus图片上传问题:UIImage无法正确转换发送请求

解决UIImage上传服务器的JSON无效与图片转换问题

错误原因

  1. JSON序列化不支持Data类型:直接将UIImage转换后的Data对象放入JSON字典中,JSONSerialization无法序列化原生Data类型,这是抛出Invalid type in JSON write (Foundation.__NSSwiftData)异常的核心原因。
  2. 请求格式不匹配:设置了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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 04:50:07