将 .MOV 视频文件作为 POST 请求的一部分发送到自己的服务器作为 Swift 中 multipart/form-data 请求的一部分不起作用

Sending .MOV video file as part of POST request to own server as part of a multipart/form-data request in Swift not working

我们正在尝试使用 Swift 和 multipart/form-data post 请求将视频从 iOS 设备或​​ iOS 模拟器发送到我们自己托管在 AWS 上的服务器.

我们在 postman 中正确设置了请求,并测试了它是否成功。我们在 post 人工响应日志中收到成功的 200 个 HTTP 状态代码,并且视频数据正在正确传输,因为我们能够在设备上播放视频以及在 AWS 上的 S3 中观看时。

但是,在 Swift 中生成 multipart/form-data 请求时,我们到目前为止还没有成功。我们最初根据以下代码片段使用 Postman 生成的代码:

import Foundation
#if canImport(FoundationNetworking)
import FoundationNetworking
#endif

var semaphore = DispatchSemaphore (value: 0)

let parameters = [
        [
                "key": "video",
                "src": "device_file_url",
                "type": "file"
        ]] as [[String : Any]]

let boundary = "Boundary-\(UUID().uuidString)"
var body = ""
var error: Error? = nil
for param in parameters {
        if param["disabled"] == nil {
                let paramName = param["key"]!
                body += "--\(boundary)\r\n"
                body += "Content-Disposition:form-data; name=\"\(paramName)\""
                if param["contentType"] != nil {
                        body += "\r\nContent-Type: \(param["contentType"] as! String)"
                }
                let paramType = param["type"] as! String
                if paramType == "text" {
                        let paramValue = param["value"] as! String
                        body += "\r\n\r\n\(paramValue)\r\n"
                } else {
                        let paramSrc = param["src"] as! String
                        let fileData = try NSData(contentsOfFile:paramSrc, options:[]) as Data
                        let fileContent = String(data: fileData, encoding: .utf8)!
                        body += "; filename=\"\(paramSrc)\"\r\n"
                          + "Content-Type: \"content-type header\"\r\n\r\n\(fileContent)\r\n"
                }
        }
}
body += "--\(boundary)--\r\n";
let postData = body.data(using: .utf8)

var request = URLRequest(url: URL(string: "https://url_to_server/")!,timeoutInterval: Double.infinity)
request.addValue("token xxxx", forHTTPHeaderField: "Authorization")
request.addValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

request.httpMethod = "POST"
request.httpBody = postData

let task = URLSession.shared.dataTask(with: request) { data, response, error in 
        guard let data = data else {
                print(String(describing: error))
                semaphore.signal()
                return
        }
        print(String(data: data, encoding: .utf8)!)
        semaphore.signal()
}

task.resume()
semaphore.wait()

这一行似乎将文件转换为字节数组根据这张图片Video data in Bytes :

let fileData = try NSData(contentsOfFile:paramSrc, options:[]) as Data

然后以下行出错(b/c 由于从上面的行中命中 nil 值而导致解包失败):

let fileContent = String(data: fileData, encoding: .utf8)!

因此我们假设问题可能是由于 .MOV/video 文件在传递到请求正文之前转换为数据对象/字符串造成的。


然后我们对 fileContent 行使用了另一种解码策略,如下所示:

let fileContent = String(decoding: fileData, as: UTF8.self)

就收到成功的 HTTP 响应代码 200 和服务器端的 videoUrl 识别已发送对象而言,这是成功的。然而,当打印 fileContent 字符串时,它是一长串随机字符,如下图所示: Swift console log of fileContent string

并且在 AWS S3 中查看端点时,资产显示没有支持格式的视频并且找到 mime 类型(所有浏览器都有相同的响应)Error of video format screenshot 表明视频到数据的转换是 incorrect/corrupted 因此无法正常工作。


我的问题是:

  1. 从 iOS 设备或​​模拟器将视频数据作为 HTTP 请求的一部分发送到服务器的最有效方法是什么? Multipart/form-data? --- 1.2) 如果 Multipart/form-data 是最好的方法,那么将视频转换为数据并作为 post 请求的一部分发送的正确方法是什么?
  2. 有没有其他方法有利于发送此类数据?

考虑到大量应用程序将视频从设备发送到服务器,我希望有关于此类主题的大量文档,但我还没有找到一个有效的解决方案。

如有任何帮助,我们将不胜感激!

简介:

我不会将它转换成字符串... 认为每个数据都可以是有效的 UTF8 字符串,这是一个很大的错误......但是一个有效的 UTF8 字符串到 Data,每次都有效。

let stringImage = String(data: anyUIImage.pngData()!, encoding: .utf8)

正常应该给nil值...

正在使用:

相反,使 body 成为 Data,而不是 String,因为最终 httpBodyData

var body = Data()

当你想追加一个String:

body += "--\(boundary)\r\n"

=>

body += Data("--\(boundary)\r\n".utf8)

如果您有 Data 参数,请直接附加它。

然后,为您的视频内容;

let paramSrc = param["src"] as! String
let fileData = try NSData(contentsOfFile:paramSrc, options:[]) as Data
let fileContent = String(data: fileData, encoding: .utf8)!
body += "; filename=\"\(paramSrc)\"\r\n"
        + "Content-Type: \"content-type header\"\r\n\r\n\(fileContent)\r\n"

应该是:

if let source = param["src"] as? String, let fileContent = try? Data(contentsOf: source) {
    body += Data("; filename=\"\(paramSrc)\"\r\n".utf8)
    body += Data("Content-Type: \"content-type header\"\r\n".utf8)
    //Now, appending the data
    body += Data("\r\n".utf8)
    body += fileContent
    body += Data("\r\n".utf8)
}

最后:

request.httpBody = body