iOS-如何使用uploadTask上传视频? [英] iOS - How to upload a video with uploadTask?
问题描述
我需要将iPhone/iPad上的mp4视频文件上传到服务器(也在后台),因此我可以通过 URLSession.uploadTask(with:URLRequest,fromFile:URL)来读取方法,但是我之前不了解如何准备请求.我需要创建一个multipart/form-data请求,因为我想附加其他字符串参数.
I need to upload an mp4 video file from iPhone/iPad to a server, also in the background, so I read that is possible with URLSession.uploadTask(with: URLRequest, fromFile: URL) method, but I don't understand how do I prepare the request before.I need to create a multipart/form-data request because I want to append other string parameters.
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如何工作?也许它将文件的数据附加到请求正文,然后自动添加边界?如果我使用此代码,则上传不起作用,我需要更改什么?
How does the uploadTask work? maybe it appends the data of the file to the request body and then adds the boundary automatically? if I use this code, the upload doesn't work, what I have to change?
更新:我已经更新了代码,现在可以使用uploadTask的completionHandler在前台执行上传,但是如果我创建后台会话并使用URLSessionDataDelegate而不是completionHandler(因为它不会(无法在后台运行),使用2 MB的文件传输速度也很慢,我该如何解决?
UPDATE: I've updated the code, now the upload works in foreground using the completionHandler of the uploadTask, but if I create a background session and using URLSessionDataDelegate instead of the completionHandler (because it doesn't work in the background), the transfer rate is very slow also with a 2 MB file, how can I solve this?
UPDATE 2 :在后台会话中,uploadTask会重新启动很多次,并且永远不会完成.
UPDATE 2: with the background session, the uploadTask restarts many times and it doesn't complete, never.
推荐答案
经过几次尝试,我看到了 URLSession.uploadTask(with:URLRequest,fromFile:URL)方法将文件附加为原始正文到请求,因此问题出在解析表单数据请求而不是原始正文请求的服务器副本.修复服务器端脚本后,使用以下代码在后台运行上传:
After some attempts, I saw the URLSession.uploadTask(with: URLRequest, fromFile: URL) method attaches the file as raw body to the request, so the problem was the server counterpart that was parsing form-data requests instead raw body requests.After I fixed the server side script, the upload works in background with this code:
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()
这篇关于iOS-如何使用uploadTask上传视频?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!