【问题标题】:Swift - Request status was 400 while uploading Video to TwitterSwift - 将视频上传到 Twitter 时请求状态为 400
【发布时间】:2018-10-04 08:22:05
【问题描述】:

我正在尝试上传,即使用我的设备将视频分享到 Twitter。到目前为止,我已经使用下面的代码来做到这一点。

     // video Upload

    func requestAccessToTwitterAccount(videoURL:NSURL,fileSize:UInt32){

        let accountStore = ACAccountStore()
        let twitterAccountType = accountStore.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)
        accountStore.requestAccessToAccounts(with: twitterAccountType, options: nil) { (granted, error) in

            if granted {
                let accounts = accountStore.accounts(with: twitterAccountType)
                if (accounts?.count)! > 0 {
                    self.twitterAccount = accounts?.last as! ACAccount
                    self.uploadVideoToTwitter(videoURL: videoURL, fileSize: fileSize)
                }
            else{
                    let error = "Please set your twitter account in Settings."
                    print(error)
                }
            }
        else {
            print("App permissions are disabled in device twitter settings, please enable it.")
        }
    }
}
    func uploadVideoToTwitter(videoURL:NSURL,fileSize: UInt32){
        print(videoURL.path!)
        if let videoData = NSData(contentsOfFile: videoURL.path!){

            self.tweetVideoInit(videoData: videoData, videoSize: Int(fileSize))
        }else{
            print("Something Wrong")
        }
    }

    func tweetVideoInit(videoData:NSData,videoSize:Int) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "INIT"
        params["total_bytes"]  = String(videoData.length)
        params["media_type"]  = "video/MOV"

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if let err = error {
                print(error!)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {

                        if let tweetID = dictionary["media_id_string"] as? String{
                            self.tweetVideoApped(videoData: videoData, videoSize: videoSize, mediaId: tweetID, chunk: 0)
                        }
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }



    func tweetVideoApped(videoData:NSData,videoSize:Int ,mediaId:String,chunk:NSInteger) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "APPEND"
        params["media_id"]  = mediaId
        params["segment_index"]  = String(chunk)

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.addMultipartData(videoData as Data!, withName: "media", type: "video/mov", filename:"mediaFile")

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if let err = error {
                print(err)

            }else{
                self.tweetVideoFinalize(mediaId: mediaId)
            }
        })
    }

    func tweetVideoFinalize(mediaId:String) {
        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()
        params["command"] = "FINALIZE"
        params["media_id"]  = mediaId

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        self.postStatus(mediaId: mediaId)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

    func postStatus(mediaId:String) {

        let uploadURL = NSURL(string:"https://api.twitter.com/1.1/statuses/update.json")

        var params = [String:String]()
        //params["status"] = twitterDescription
        params["media_ids"]  = mediaId

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in

            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print("video uploaded")
                        let alert = UIAlertController(title: "Success", message: "video uploaded successfully.", preferredStyle: UIAlertControllerStyle.alert)
                        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                        self.present(alert, animated: true, completion: nil)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

现在问题是这样的,我不确定问题出在哪里,但是当我尝试上传小于10 secs 的视频时,它已上传成功,但是当我尝试视频时超过 10 秒,它会给出 Request status 400 错误,并且视频无法上传。

注意:-我的视频格式是.MOV,大​​小约为6.4MB。所以我猜它是根据Twitter 的视频上传指南接受的。

仅供参考:-我也提到了这个链接 - Twitter Upload Demo

还有Official Documentation 建议以下限制,其中 我不超过。

有人可以帮我解决为什么会出现这个问题。

【问题讨论】:

  • Http 代码 400 是“错误请求”。因此,您发送的请求对 API 无效。可能缺少参数、文件大小太大等。您是否已经在 Stackoverflow 上搜索过答案?这已经被问过很多次了。
  • 是的 @Scriptable 已经搜索过这个,他们建议参数是错误的,但在我的情况下,他们不是因为他们在 6-7 秒的视频中工作,但不是在 10+ 秒的视频中。 ?所以我想问题是不同的
  • 所以我猜你正在达到 API 限制。如果它适用于小视频但不适用于较大的视频,那么您必须达到上传/速率限制。
  • 是的,在这一点上我可能同意你的看法,但我在一些论坛上读到这似乎仅适用于 .mov 格式,大小不是问题,因为如果我上传使用 URL 的视频很容易上传,如果是 20+ 秒,那么也很容易上传。那么你能解释一下为什么会发生这种情况
  • 我不是 twitter API 开发人员,也许你应该联系他们寻求支持

标签: ios swift twitter


【解决方案1】:

这是我之前使用的代码,对我来说很好用。试试这个

let account = ACAccountStore()
            let accountType = account.accountType(
                withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)

            account.requestAccessToAccounts(with: accountType, options: nil,
                                            completion: {(success, error) in

                                                if success {
                                                    let arrayOfAccounts =
                                                        account.accounts(with: accountType)

                                                    if (arrayOfAccounts?.count)! > 0 {
                                                        let twitterAccount = arrayOfAccounts?.last as! ACAccount
                                                        let message = “your text here”
                                                        print(twitterAccount)


                                                        self.socialVideo.uploadTwitterVideo(self.coachController?.videoData as Data!, comment: message, account: twitterAccount, withCompletion: { (success, value) in


                                                            if success == true {

                                                                self.showToast(message: "Uploaded Succesfully")
                                                            }

                                                        })
                                                    }
                                                }
            })

SocialVideo Helper 下载链接 -> https://github.com/liu044100/SocialVideoHelper

【讨论】:

  • 你没有包含你用来上传视频的函数self.socialVideo.uploadTwitterVideo()。
  • 您必须在代码中下载 SocialVideoHelper (objective-c) 文件才能使用它。
  • 您能否编辑答案并发布链接。
  • 完成。请检查并让我知道它是否有效。谢谢
  • 它是如何为我工作的,但对我来说不是。任何方式感谢您的回答。真的很感谢你的努力,投了赞成票。
【解决方案2】:

在研究了Docs 并没有找到任何方法之后。对我有用的东西就像 Compressing 视频。

我使用以下代码压缩视频并将其转换为.m4v 格式以及它对我的工作原理。

注意:-上传视频的限制是15MB30sec Max

上传视频到Twitter的完整代码是:

func imagePickerController(_ picker: UIImagePickerController,
                           didFinishPickingMediaWithInfo info: [String : Any])
{
    if  let video = info[UIImagePickerControllerMediaURL] as? URL{
        let asset = AVURLAsset(url: video)
        let durationInSeconds = asset.duration.seconds
        print(durationInSeconds)

        if durationInSeconds < 30{
            arrImageURL.removeAll()
            btnSelectImage.setBackgroundImage(nil, for: .normal)
            btnSelectImage.setTitle("Select Image to attach", for: .normal)
            videoURL = video
            print(videoURL)
            let innerVideoURL = video
            let data = NSData(contentsOf: innerVideoURL as URL)!
            print("File size before compression: \(Double(data.length / 1048576)) mb")
            let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".m4v")
            compressVideo(inputURL: innerVideoURL , outputURL: compressedURL) { (exportSession) in
                guard let session = exportSession else {
                    return
                }

                switch session.status {
                case .unknown:
                    break
                case .waiting:
                    break
                case .exporting:
                    break
                case .completed:
                    self.videoURL = compressedURL
                case .failed:
                    break
                case .cancelled:
                    break
                }
            }
        }else{
            showAlertWithTitle(title: "Alert!", message: "Video Length cannot be more that 30Sec to upload!")
        }

    }
    picker.dismiss(animated: true, completion: nil);
}

func compressVideo(inputURL: URL, outputURL: URL, handler:@escaping (_ exportSession: AVAssetExportSession?)-> Void) {
        let urlAsset = AVURLAsset(url: inputURL, options: nil)
        guard let exportSession = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetMediumQuality) else {
            handler(nil)
            return
        }

        exportSession.outputURL = outputURL
        exportSession.outputFileType = AVFileType.mov
        exportSession.shouldOptimizeForNetworkUse = true
        exportSession.exportAsynchronously { () -> Void in
            handler(exportSession)
        }
    }

然后依次调用以下方法上传视频:

    // video Upload

    func requestAccessToTwitterAccount(videoURL:NSURL,fileSize:UInt32){

        let accountStore = ACAccountStore()
        let twitterAccountType = accountStore.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)
        accountStore.requestAccessToAccounts(with: twitterAccountType, options: nil) { (granted, error) in

            if granted {
                let accounts = accountStore.accounts(with: twitterAccountType)
                if (accounts?.count)! > 0 {
                    self.twitterAccount = accounts?.last as! ACAccount
                    self.uploadVideoToTwitter(videoURL: videoURL, fileSize: fileSize)
                }
            else{
                    let error = "Please set your twitter account in Settings."
                    print(error)
                }
            }
        else {
            print("App permissions are disabled in device twitter settings, please enable it.")
        }
    }
}
    func uploadVideoToTwitter(videoURL:NSURL,fileSize: UInt32){
        print(videoURL.path!)
        if let videoData = NSData(contentsOfFile: videoURL.path!){

            self.tweetVideoInit(videoData: videoData, videoSize: Int(fileSize))
        }else{
            print("Something Wrong")
        }
    }

    func tweetVideoInit(videoData:NSData,videoSize:Int) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "INIT"
        params["total_bytes"]  = String(videoData.length)
        params["media_type"]  = "video/m4v"

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            if error != nil {
                print(error!)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        if let tweetID = dictionary["media_id_string"] as? String{
                            self.tweetVideoApped(videoData: videoData, videoSize: videoSize, mediaId: tweetID, chunk: 0)
                        }
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }



    func tweetVideoApped(videoData:NSData,videoSize:Int ,mediaId:String,chunk:NSInteger) {

        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()

        params["command"] = "APPEND"
        params["media_id"]  = mediaId
        params["segment_index"]  = String(chunk)

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.addMultipartData(videoData as Data!, withName: "media", type: "video/m4v", filename:"mediaFile")

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            print(responseData!)
            if let err = error {
                print(err)

            }else{
                self.tweetVideoFinalize(mediaId: mediaId)
            }
        })
    }

    func tweetVideoFinalize(mediaId:String) {
        let uploadURL = NSURL(string:"https://upload.twitter.com/1.1/media/upload.json")

        var params = [String:String]()
        params["command"] = "FINALIZE"
        params["media_id"]  = mediaId

         print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;
        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            print(responseData!)
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        if self.videoURL != nil{
                            self.postStatusVideo(mediaId: mediaId)
                        }else{
                            print("Image Post Called")
                            if self.arrMediaIdString.count == self.arrImage.count{
                                self.postStatusMultipleImages(arrMediaId: self.arrMediaIdString, statusText: "Demo Multi Images")
                            }
                        }
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

    func postStatusMultipleImages(arrMediaId:[String],statusText:String) {

        let uploadURL = NSURL(string:"https://api.twitter.com/1.1/statuses/update.json")

        var params = [String:Any]()
        params["status"] = statusText
        params["media_ids"]  = arrMediaId

        print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
            print(responseData!)
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        print("video uploaded")
                        let alert = UIAlertController(title: "Success", message: "video uploaded successfully.", preferredStyle: UIAlertControllerStyle.alert)
                        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                        self.present(alert, animated: true, completion: nil)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

    func postStatusVideo(mediaId:String) {

        let uploadURL = NSURL(string:"https://api.twitter.com/1.1/statuses/update.json")

        var params = [String:String]()
        params["status"] = "Testing Video"
        params["media_ids"]  = mediaId

         print(params)

        let postRequest = SLRequest(forServiceType: SLServiceTypeTwitter,
                                    requestMethod: SLRequestMethod.POST,
                                    url: uploadURL as URL!,
                                    parameters: params)

        postRequest?.account = self.twitterAccount;

        postRequest?.perform(handler: { ( responseData, urlREsponse,error) in
           print(responseData!)
            if let err = error {
                print(err)
            }else{
                do {
                    let object = try JSONSerialization.jsonObject(with: responseData! as Data, options: .allowFragments)
                    if let dictionary = object as? [String: AnyObject] {
                        print(dictionary)
                        print("video uploaded")
                        let alert = UIAlertController(title: "Success", message: "video uploaded successfully.", preferredStyle: UIAlertControllerStyle.alert)
                        alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
                        self.present(alert, animated: true, completion: nil)
                    }
                }
                catch {
                    print(error)
                }
            }
        })
    }

最后像这样使用它:

var fileSizeValue = getVideoSize(contentUrl: videoURL)
requestAccessToTwitterAccount(videoURL: videoURL as NSURL, fileSize: UInt32(fileSizeValue))

以及计算视频大小的函数:

func getVideoSize(contentUrl:URL) -> UInt64{
    do {
        let fileAttribute: [FileAttributeKey : Any] = try FileManager.default.attributesOfItem(atPath: contentUrl.path)
        if let fileNumberSize: NSNumber = fileAttribute[FileAttributeKey.size] as? NSNumber {
            return UInt64(truncating: fileNumberSize)
        }
    } catch {
        print(error.localizedDescription)
    }
   return 0
}

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-06
    • 2019-11-21
    • 1970-01-01
    • 2011-09-11
    • 2021-02-11
    • 2023-03-06
    • 1970-01-01
    • 2011-02-25
    相关资源
    最近更新 更多