我需要将一个mp4视频文件从iPhone / iPad上传到服务器,也在后台,所以我读到了 URLSession.uploadTask(带:URLRequest,fromFile:URL)方法,但我不明白我如何准备请求。我需要创建一个multipart / form-data请求,因为我想追加其他字符串参数。
func requestBodyFor(video: URL) -> Data? {
let url = URL(string: "url_of_upload_handler.php")!
let parameters = ["type":"video", "user":"112"]
do {
let kBoundary = "Boundary-\(UUID().uuidString)"
let kStartTag = "--%@\r\n"
let kEndTag = "\r\n"
let kContent = "Content-Disposition: form-data; name=\"%@\"\r\n\r\n"
var body = Data()
let videoData = try Data(contentsOf: video)
// parameters
for (key,value) in parameters {
body.append(String(format: kStartTag, kBoundary).data(using: String.Encoding.utf8)!)
body.append(String(format: kContent, key).data(using: String.Encoding.utf8)!)
body.append(value.data(using: String.Encoding.utf8)!)
body.append(String(format: kEndTag).data(using: String.Encoding.utf8)!)
}
//Video data
body.append(String(format: kStartTag, boundary).data(using: String.Encoding.utf8)!)
body.append(String(format: "Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", "file", video.lastPathComponent).data(using: String.Encoding.utf8)!)
body.append("Content-Type: video/mp4\r\n\r\n".data(using: String.Encoding.utf8)!)
body.append(videoData)
body.append(String(format: kEndTag).data(using: String.Encoding.utf8)!)
// close form
body.append("--\(boundary)--\r\n".data(using: String.Encoding.utf8)!)
return body
} catch let error {
print(error)
return nil
}
}
if let body = requestBodyFor(video: fileUrl) {
let contentType = "multipart/form-data; boundary=\(kBoundary)"
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue(contentType, forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.uploadTask(with: request, from: body) { data, response, error in
guard error == nil && data != nil else {
return
}
if let data = String(data: data!, encoding: String.Encoding.utf8) {
print(data)
}
}
task.resume()
}
uploadTask如何运作?也许它会将文件的数据附加到请求主体,然后自动添加边界?如果我使用这个代码,上传不起作用,我必须改变什么?
更新:我已经更新了代码,现在使用uploadTask的completionHandler在上游工作,但是如果我创建后台会话并使用URLSessionDataDelegate而不是completionHandler(因为它没有在后台工作,传输速度非常慢也有2 MB文件,我该如何解决?
UPDATE 2 :使用后台会话,uploadTask重启多次,但从未完成。
答案 0 :(得分:5)
经过一些尝试,我看到 URLSession.uploadTask(带:URLRequest,fromFile:URL)方法将文件作为原始主体附加到请求中,因此问题是解析的服务器对应物表单数据请求而不是原始身体请求。修复服务器端脚本后,上传工作在后台使用此代码:
var request = URLRequest(url: "my_url")
request.httpMethod = "POST"
request.setValue(file.lastPathComponent, forHTTPHeaderField: "filename")
let sessionConfig = URLSessionConfiguration.background(withIdentifier: "it.example.upload")
sessionConfig.isDiscretionary = false
sessionConfig.networkServiceType = .video
let session = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: OperationQueue.main)
let task = session.uploadTask(with: request, fromFile: file)
task.resume()
答案 1 :(得分:1)
从2020年开始的解决方案,其中包含本机URLSession
,可以使用uploadTask
和multipart/form-data
运行后台上传:
multipart/form-data
对NodeJS服务器的要求URLSession
的部分上进行了一些更改:let config = URLSessionConfiguration.background(withIdentifier: "uniqueID")
let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
// This line is important: here we use withStreamedRequest
let task = session.uploadTask(withStreamedRequest: request)
task.resume()
关于我的服务器端的一些信息:
希望获得帮助
答案 2 :(得分:0)
有时,服务器从表单数据读取文件更容易。例如,flask框架可以通过request.files轻松读取以form-data格式上传的文件。 Alamofire提供了一种简便的方法
df1<-df %>%
mutate_at(vars(ends_with("x1")),factor,
ifelse(x1>=3 & x1 <=12,0,ifelse(x1==1, 0,
ifelse(x1==2, 1,0))))
通过这种方式,文件将以表格数据的格式上传。