Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/118.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS-如何使用uploadTask上传视频?_Ios_Swift3_Nsurlsessionuploadtask - Fatal编程技术网

iOS-如何使用uploadTask上传视频?

iOS-如何使用uploadTask上传视频?,ios,swift3,nsurlsessionuploadtask,Ios,Swift3,Nsurlsessionuploadtask,我需要将一个mp4视频文件从iPhone/iPad上传到服务器,也在后台,所以我读到可以使用URLSession.uploadTask(使用:URLRequest,fromFile:URL)方法,但我不明白之前如何准备请求。我需要创建一个多部分/表单数据请求,因为我想附加其他字符串参数 func requestBodyFor(video: URL) -> Data? { let url = URL(string: "url_of_upload_handler.php")!

我需要将一个mp4视频文件从iPhone/iPad上传到服务器,也在后台,所以我读到可以使用URLSession.uploadTask(使用:URLRequest,fromFile:URL)方法,但我不明白之前如何准备请求。我需要创建一个多部分/表单数据请求,因为我想附加其他字符串参数

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的completionHandler在前台工作,但是如果我创建一个后台会话,并使用URLSessionDataDelegate而不是completionHandler(因为它在后台不工作),那么对于一个2 MB的文件,传输速度也非常慢,我怎样才能解决这个问题


更新2:在后台会话中,uploadTask会多次重新启动,但从未完成。

经过一些尝试后,我看到了URLSession.uploadTask(with: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()

有时,服务器更容易从表单数据中读取文件。例如,flask框架可以通过request.files轻松读取以表单数据格式上传的文件。 Alamofire提供了一种简单的方法来实现这一点

AF.upload(multipartFormData: { multipartFormData in
                multipartFormData.append(FilePath, withName: FilePath.lastPathComponent)
            }, to: url).responseJSON { response in
                    debugPrint(response)
            }

通过这种方式,文件将以表单数据的格式上载。

解决方案,自2020年起,使用native
URLSession
运行后台上载,使用
uploadTask
多部分/表单数据

  • 我接着按照NodeJS服务器的要求设置了对
    多部分/表单数据的请求
  • 然后我对用于设置
    URLSession
    的部分做了一些更改:
let config=URLSessionConfiguration.background(带有标识符:“uniqueID”)
let session=URLSession(配置:config,委托:self,委托队列:nil)
//这一行很重要:这里我们使用withStreamedRequest
let task=session.uploadTask(withStreamedRequest:request)
task.resume()
关于我的服务器端:

  • 它是用NodeJS和Express编写的
  • 文件上传是由Multer处理的:我这样做是非常标准的,你可以在许多在线教程中找到

希望此帮助使用alamofire。如果可能,我不会使用任何外部框架来执行此操作。请参见:示例显示dataTask(它在后台不工作)和downloadTask,我需要working uploadTask示例您需要为后台任务配置。这不取决于上传任务或数据任务。谢谢,这非常有用!您是否介意分享您必须对服务器对应方执行的操作的详细信息?谢谢,这帮助我意识到我没有将参数设置为true以了解如何将文件放入服务器端@谢谢你,这个链接真的很有用。您是如何从委派中获得服务器响应的?我只是使用
didcompletewitheror
检查我的请求是否完成,我没有得到服务器响应,您可能需要自己在谷歌上搜索。