【问题标题】:Upload video to Vimeo using URLSession使用 URLSession 将视频上传到 Vimeo
【发布时间】:2023-03-07 07:46:01
【问题描述】:

我正在尝试使用他们的 rest API 将视频上传到 Vimeo。 首先我做一个 POST,在 API 上创建视频,然后我从相机中选择视频,并发送一个带有一些参数的 PATCH。 问题是,视频似乎上传成功,我得到一个没有任何错误的 HTML,似乎成功,但在网站上没有显示视频,KB 大小只有 0。

这是我的 PATCH 方法:

    let request = NSMutableURLRequest(url: "https://api.vimeo.com/me/videos")
    request.httpMethod = "PATCH"
    request.cachePolicy = .reloadIgnoringLocalCacheData
    request.httpBody = mediaData // Data()
    request.setValue("Upload-Offset", forHTTPHeaderField: "0")
    request.setValue("Content-Type", forHTTPHeaderField: "application/offset+octet-stream")
    request.setValue("Authorization", forHTTPHeaderField: "Bearer 1233131312")
    request.setValue("Tus-Resumable", forHTTPHeaderField: "1.0.0")
    let newTask = session.uploadTask(withStreamedRequest: request)
    newTask.resume()

并且已经尝试过:

request.httpBodyStream = InputStream(data: mediaData)

或:

session.uploadTask(with: request, from: data)

这是来自 VIMEO 的文档:

https://developer.vimeo.com/api/upload/videos

谁能有一个实际有效的例子或sn-p?

[更新]:

发出请求的类:

import Foundation

case get
case post
case put
case delete
case patch

var verbName: String {
    switch self {
    case .get:
        return "GET"
    case .post:
        return "POST"
    case .put:
        return "PUT"
    case .delete:
        return "DELETE"
    case .patch:
        return "PATCH"
    }
}

var containsBody: Bool {
    return self == .post || self == .put || self == .patch
}
}

final class MediaUploader: URLSessionTaskDelegate, URLSessionDataDelegate {

    private let dispatchGroup = DispatchGroup()
    private let globalSSLEnabled: Bool = true
    var outputStream: OutputStream? = nil
    private var buffer:NSMutableData = NSMutableData()

    convenience init?(domain: String) {
        self.init(domain: domain)
    }

    func request(verb: HTTPVerb, action: String, parameters: JSONDictionary = [:], headers: [String : String] = [:], sslEnabled: Bool = true, media: MediaData, completion: @escaping (_ response: HTTPResponse) -> Void) {
        let sslEnabled = self.globalSSLEnabled || sslEnabled
        guard let request = buildRequest(verb: verb, action: action, parameters: parameters, media: media, sslEnabled: sslEnabled) else {
            return
        }

        headers.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }

        let session = buildURLSession(sslEnabled: sslEnabled)

        conditionalLog(items: "REQUEST [\(verb.verbName)]")
        conditionalLog(items: "URL: \(request.url?.absoluteString ?? "[invalid]")")
        conditionalLog(items: "Headers: \(String(describing: request.allHTTPHeaderFields))")
        conditionalLog(items: "Parameters: \(parameters)")
        createSessionWithDataTask(session: session, request: request as URLRequest, mediaData: media, completion: completion)
    }

    func buildURLSession(sslEnabled: Bool) -> URLSession {
      if !sslEnabled {
          return URLSession(configuration: .default)
      }

      let configuration = URLSessionConfiguration.default
      let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)

      return session
    }

    func createSessionWithDataTask(session: URLSession, request: URLRequest, mediaData: MediaData,completion: @escaping (HTTPResponse) -> Void) {
        let queue = DispatchQueue(label: "com.lassie.dispatchgroup", attributes: .concurrent, target: nil)
        dispatchGroup.enter()
        queue.async(group: dispatchGroup) {
            self.dataTaskWorker(session: session, request: request as URLRequest, mediaData: mediaData, completion: completion)
            self.dispatchGroup.leave()
        }
    }

    func dataTaskWorker(session: URLSession, request: URLRequest, mediaData: MediaData, completion: @escaping (_ response: HTTPResponse) -> Void) {
        guard let data = mediaData.data() else {
            return
        }
        // let newTask = session.uploadTask(withStreamedRequest: request)
        // let newTask = session.uploadTask(with: request, from: data)
        //session.uploadTask(with: request, from: data)

        let task = session.uploadTask(withStreamedRequest: request) { data, response, error in
            self.conditionalLog(items: "RESPONSE: \(String(describing: response))")

            if let eRROR = error {
                self.conditionalLog(items: "ERROR : \(String(describing: eRROR))")
            }
            self.parseResponse(data: data, response: response, error: error, completion: completion)
            session.finishTasksAndInvalidate()
        }
        newTask.resume()
    }

    func buildRequest(verb: HTTPVerb, action: String, parameters: JSONDictionary = [:], media: MediaData, sslEnabled: Bool) -> NSMutableURLRequest? {
        let suffix = buildAction(verb: verb, action: action, parameters: parameters)
        guard let fullUrl = suffix.isEmpty ? baseURL(sslEnabled: sslEnabled) : URL(string: suffix, relativeTo: baseURL(sslEnabled: sslEnabled)), let mediaData = media.data() else {
            assert(false, "Invalid url/parameters")
            return nil
        }

        let request = NSMutableURLRequest(url: fullUrl)
        request.httpMethod = verb.verbName
        request.cachePolicy = .reloadIgnoringLocalCacheData
        request.httpBody = mediaData
//        request.httpBodyStream = InputStream(data: mediaData)
        return request
    }

    // MARK: URLSessionDataTask

    func urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) {
        self.closeStream()

        var inStream: InputStream? = nil
        var outStream: OutputStream? = nil
        Stream.getBoundStreams(withBufferSize: 4096, inputStream: &inStream, outputStream: &outStream)
        self.outputStream = outStream

        completionHandler(inStream)
    }

    private func closeStream() {
        if let stream = self.outputStream {
            stream.close()
            self.outputStream = nil
        }
    }

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        buffer.append(data)
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
        let percentageSent = Double(totalBytesSent) / Double(totalBytesExpectedToSend)
        print("PERCENTAGE - \(percentageSent)")
    }

    private func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
        completionHandler(.allow)
    }

    private func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        if let e = error {
        print("ERROR")
        } else {
            self.conditionalLog(items: "RESPONSE DATA: \(String(data: buffer as Data, encoding: .utf8))")
        }
    }
}

【问题讨论】:

  • 不相关,但这是 Swift。使用URLRequest,而不是NS[Mutable]URLRequest
  • 什么是“PATCH”http方法?你不是说“POST”吗?
  • 你为什么不试试github.com/vimeo/VimeoUpload。如果您仍想手动完成,我可以检查您的代码,
  • @Gihan,我不想在项目上添加另一个依赖项,它只是一个上传方法

标签: ios swift video upload vimeo


【解决方案1】:

您正在使用session.uploadTask(withStreamedRequest: request)。后端文件大小为 0 的原因是您没有关闭流,例如inputStream.finished = true。因此,您必须弄清楚何时要关闭该流。

无论如何,因为您已经准备好数据。我想说你可以使用uploadTask(with:from:completionHandler:),甚至可以切换到uploadTask(with:fromFile:completionHandler:)

【讨论】:

  • 对不起,忘了放整个代码,但我确实关闭了流,你可以在课堂上检查一下
  • 你为什么还在用httpBody而不是httpBodyStream
猜你喜欢
  • 2013-04-23
  • 1970-01-01
  • 2020-02-27
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
  • 2016-01-12
  • 1970-01-01
  • 2019-02-26
相关资源
最近更新 更多