【问题标题】:Send POST parameters with MultipartFormData using Alamofire, in iOS Swift在 iOS Swift 中使用 Alamofire 使用 MultipartFormData 发送 POST 参数
【发布时间】:2015-11-04 02:41:50
【问题描述】:

我第一次使用 Alamofire。我正在使用最新版本的 Alamofire 1.3.1。我想在一次 API 调用中发送一张图片、一段视频和一些 POST 参数。我正在使用多部分表单数据。多部分模块正在工作。我在发送额外的 POST 参数params 时遇到问题。下面是我的代码。 “params”是包含额外参数的字典吗?如何在请求中附加这些 POST 参数。请帮忙

        var fullUrl :String = Constants.BASE_URL + "/api/CompleteChallenge"
         var params = [
        "authKey": Constants.AuthKey,
        "idUserChallenge": "16",
        "comment": "",
        "photo": imagePath,
        "video": videoPath,
        "latitude": "1",
        "longitude": "1",
        "location": "india"
    ]

    let imagePathUrl = NSURL(fileURLWithPath: imagePath!)
    let videoPathUrl = NSURL(fileURLWithPath: videoPath!)

        Alamofire.upload(
        .POST,
        URLString: fullUrl, // http://httpbin.org/post
        multipartFormData: { multipartFormData in
            multipartFormData.appendBodyPart(fileURL: imagePathUrl!, name: "photo")
            multipartFormData.appendBodyPart(fileURL: videoPathUrl!, name: "video")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.responseJSON { request, response, JSON, error in

                  }
                }
            case .Failure(let encodingError):

            }
        }
    )

【问题讨论】:

标签: ios swift http alamofire


【解决方案1】:

我终于找到了解决方案:)。

我们可以将请求中的数据作为 multipartformdata 附加。

下面是我的代码。

  Alamofire.upload(
        .POST,
        URLString: fullUrl, // http://httpbin.org/post
        multipartFormData: { multipartFormData in
            multipartFormData.appendBodyPart(fileURL: imagePathUrl!, name: "photo")
            multipartFormData.appendBodyPart(fileURL: videoPathUrl!, name: "video")
            multipartFormData.appendBodyPart(data: Constants.AuthKey.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"authKey")
            multipartFormData.appendBodyPart(data: "\(16)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"idUserChallenge")
            multipartFormData.appendBodyPart(data: "comment".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"comment")
            multipartFormData.appendBodyPart(data:"\(0.00)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"latitude")
            multipartFormData.appendBodyPart(data:"\(0.00)".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"longitude")
            multipartFormData.appendBodyPart(data:"India".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name :"location")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.responseJSON { request, response, JSON, error in


                }
            case .Failure(let encodingError):

            }
        }
    )

编辑 1: 对于那些试图发送数组而不是浮点数、整数或字符串的人,他们可以在 Json 字符串中转换他们的数组或任何类型的数据结构,传递这个 JSON 字符串作为普通字符串。并在后端解析这个 json 字符串以获得原始数组

【讨论】:

  • 如果我有一个数组作为参数然后。
  • 您必须将数组转换为字符串。不能在参数中发送数组。
  • 好吧,实际上我的后端 pHP 希望我将数组作为参数发送,因为该 API 适用于 android。因此,如果我以字符串形式发送它,那么我还需要在我的后端 pHP 中进行修改......对。
  • 我可以打印 multipartFormData 以便知道要发送到服务器的内容吗?
  • 任何人都可以为 swift 3 和 Alamofire 4 更新它吗?将参数传递给附加函数时,我无法将参数转换为类型数据。
【解决方案2】:

在 Alamofire 4 中,添加文件数据之前添加正文数据很重要!

let parameters = [String: String]()
[...]
self.manager.upload(
    multipartFormData: { multipartFormData in
        for (key, value) in parameters {
            multipartFormData.append(value.data(using: .utf8)!, withName: key)
        }
        multipartFormData.append(imageData, withName: "user", fileName: "user.jpg", mimeType: "image/jpeg")
    },
    to: path,
    [...]
)

【讨论】:

  • 音频文件怎么样? - 我尝试以这种形式发送音频文件:multipartFormData.append(audioLocalPath, withName: "file", fileName: "file", mimeType: "application/octet-stream") 但出现此错误:multipartEncodingFailed(Alamofire.AFError .MultipartEncodingFailureReason.bodyPartFileNotReachableWithError(file:///var/mobile/Containers/......./Documents/item.mp3, NSUnderlyingError=0x16049100 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}} )) - 问题出在哪里? - 错误的请求或错误的音频路径?
  • No such file or directory 看起来像是一个错误的文件路径
  • 是的! - 我知道这是错误的路径,但我尝试使用以下方式获取路径:`let localPath = audioURL.appendingPathComponent(audioName!)`,它适用于图像但不适用于音频
  • 您好 Alexander,我开始使用 swift 3.0,现在我正在使用 Almofire 4。我尝试上传图像,但它不适合我。即使我没有得到服务器的响应。
  • “在 Alamofire 4 中,在添加文件数据之前添加正文数据很重要” 这句话对我来说意义重大。我被困了 2 天,因为我先添加了图像,然后正文和服务器返回 400。谢谢,但在我早期使用 alamofire 4 的应用程序中并没有发生这种情况。这是第一次,非常奇怪。谁能解释为什么? +1
【解决方案3】:

这就是我解决问题的方法

let parameters = [
            "station_id" :        "1000",
            "title":      "Murat Akdeniz",
            "body":        "xxxxxx"]

let imgData = UIImageJPEGRepresentation(UIImage(named: "1.png")!,1)



    Alamofire.upload(
        multipartFormData: { MultipartFormData in
        //    multipartFormData.append(imageData, withName: "user", fileName: "user.jpg", mimeType: "image/jpeg")

            for (key, value) in parameters {
                MultipartFormData.append(value.data(using: String.Encoding.utf8)!, withName: key)
            }

        MultipartFormData.append(UIImageJPEGRepresentation(UIImage(named: "1.png")!, 1)!, withName: "photos[1]", fileName: "swift_file.jpeg", mimeType: "image/jpeg")
        MultipartFormData.append(UIImageJPEGRepresentation(UIImage(named: "1.png")!, 1)!, withName: "photos[2]", fileName: "swift_file.jpeg", mimeType: "image/jpeg")


    }, to: "http://platform.twitone.com/station/add-feedback") { (result) in

        switch result {
        case .success(let upload, _, _):

            upload.responseJSON { response in
                print(response.result.value)
            }

        case .failure(let encodingError): break
            print(encodingError)
        }


    }

【讨论】:

    【解决方案4】:

    Swift 3 / Alamofire 4.0 accepted answer 的附录)

    要在 Swift 3 / Alamofire 4.0 中附加到 multipartFormData,请使用 MultipartFormData 的以下方法:

    public func append(_ data: Data, withName name: String) { /* ... */ }
    

    并且,要将String 转换为Data,使用Stringdata(using:) 方法。例如,

    multipartFormData.append("comment".data(using: .utf8)!, withName: "comment")
    

    【讨论】:

    • 谢谢。你有URLRequestConvertible参数的例子吗?
    • 我必须附加 Int 数据,怎么办?你能帮帮我吗?
    【解决方案5】:

    对于 alamofire 4 使用这个 ..

            Alamofire.upload(multipartFormData: { (multipartFormData) in
    
                multipartFormData.append(fileUrl, withName: "video")
           //fileUrl is your file path in iOS device and withName is parameter name
    
            }, to:"http://to_your_url_path")
            { (result) in
                switch result {
                case .success(let upload, _ , _):
    
                    upload.uploadProgress(closure: { (progress) in
    
                        print("uploding")
                    })
    
                    upload.responseJSON { response in
    
                       print("done")
    
                    }
    
                case .failure(let encodingError):
                    print("failed")
                    print(encodingError)
    
                }
            }
    

    【讨论】:

      【解决方案6】:

      在 Swift 3.x 中,我们可以使用下面的 alamofire 上传方法来上传带参数的图像-

      static func uploadImageData(inputUrl:String,parameters:[String:Any],imageName: String,imageFile : UIImage,completion:@escaping(_:Any)->Void) {
      
              let imageData = UIImageJPEGRepresentation(imageFile , 0.5)
      
              Alamofire.upload(multipartFormData: { (multipartFormData) in
      
                  multipartFormData.append(imageData!, withName: imageName, fileName: "swift_file\(arc4random_uniform(100)).jpeg", mimeType: "image/jpeg")
      
                  for key in parameters.keys{
                      let name = String(key)
                      if let val = parameters[name!] as? String{
                          multipartFormData.append(val.data(using: .utf8)!, withName: name!)
                      }
                  }
              }, to:inputUrl)
              { (result) in
                  switch result {
                  case .success(let upload, _, _):
      
                      upload.uploadProgress(closure: { (Progress) in
                      })
      
                      upload.responseJSON { response in
      
                          if let JSON = response.result.value {
                              completion(JSON)
                          }else{
                              completion(nilValue)
                          }
                      }
      
                  case .failure(let encodingError):
                      completion(nilValue)
                  }
      
              }
      
          }
      

      注意:另外,如果我们的参数是密钥对数组,那么我们可以 使用

       var arrayOfKeyPairs = [[String:Any]]()
       let json = try? JSONSerialization.data(withJSONObject: arrayOfKeyPairs, options: [.prettyPrinted])
       let jsonPresentation = String(data: json!, encoding: .utf8)
      

      【讨论】:

        【解决方案7】:

        好吧,由于多部分表单数据旨在用于二进制(而不是文本)数据传输,我认为将数据以编码形式发送到 String 是不好的做法。

        另一个缺点是无法发送更复杂的参数,例如 JSON。

        也就是说,更好的选择是以二进制形式发送所有数据,即数据。

        说我需要发送这些数据

        let name = "Arthur"
        let userIDs = [1,2,3]
        let usedAge = 20
        

        ...连同用户的图片:

        let image = UIImage(named: "img")!
        

        为此,我会将文本数据转换为 JSON,然后与图像一起转换为二进制:

        //Convert image to binary
        let data = UIImagePNGRepresentation(image)!
        
        //Convert text data to binary
        let dict: Dictionary<String, Any> = ["name": name, "userIDs": userIDs, "usedAge": usedAge]
        userData = try? JSONSerialization.data(withJSONObject: dict)
        

        然后,最后通过 Multipart Form Data 请求发送:

        Alamofire.upload(multipartFormData: { (multiFoormData) in
                multiFoormData.append(userData, withName: "user")
                multiFoormData.append(data, withName: "picture", mimeType: "image/png")
            }, to: url) { (encodingResult) in
                ...
            }
        

        【讨论】:

          【解决方案8】:

          适用于 Swift 4.2 / Alamofire 4.7.3

          Alamofire.upload(multipartFormData: { multipart in
              multipart.append(fileData, withName: "payload", fileName: "someFile.jpg", mimeType: "image/jpeg")
              multipart.append("comment".data(using: .utf8)!, withName :"comment")
          }, to: "endPointURL", method: .post, headers: nil) { encodingResult in
              switch encodingResult {
              case .success(let upload, _, _):
                  upload.response { answer in
                      print("statusCode: \(answer.response?.statusCode)")
                  }
                  upload.uploadProgress { progress in
                      //call progress callback here if you need it
                  }
              case .failure(let encodingError):
                  print("multipart upload encodingError: \(encodingError)")
              }
          }
          

          您还可以查看CodyFire lib,它使用 Codable 让 API 调用更容易。 使用 CodyFire 的多部分呼叫示例

          //Declare your multipart payload model
          struct MyPayload: MultipartPayload {
              var attachment: Attachment //or you could use just Data instead
              var comment: String
          }
          
          // Prepare payload for request
          let imageAttachment = Attachment(data: UIImage(named: "cat")!.jpeg(.high)!,
                                           fileName: "cat.jpg",
                                           mimeType: .jpg)
          let payload = MyPayload(attachment: imageAttachment, comment: "Some text")
          
          //Send request easily
          APIRequest("endpoint", payload: payload)
              .method(.post)
              .desiredStatus(.created) //201 CREATED
              .onError { error in
                  switch error.code {
                  case .notFound: print("Not found")
                  default: print("Another error: " + error.description)
                  }
              }.onSuccess { result in
                  print("here is your decoded result")
              }
          //Btw normally it should be wrapped into an extension
          //so it should look even easier API.some.upload(payload).onError{}.onSuccess{}
          

          您可以查看lib's readme 中的所有示例

          【讨论】:

            【解决方案9】:
            func funcationname()
            {
            
                var parameters = [String:String]()
                let apiToken = "Bearer \(UserDefaults.standard.string(forKey: "vAuthToken")!)"
                let headers = ["Vauthtoken":apiToken]
                let mobile = "\(ApiUtillity.sharedInstance.getUserData(key: "mobile"))"
                parameters = ["first_name":First_name,"last_name":last_name,"email":Email,"mobile_no":mobile]
            
                print(parameters)
                ApiUtillity.sharedInstance.showSVProgressHUD(text: "Loading...")
                let URL1 = ApiUtillity.sharedInstance.API(Join: "user/update_profile")
                let url = URL(string: URL1.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)
                var urlRequest = URLRequest(url: url!)
                urlRequest.httpMethod = "POST"
                urlRequest.allHTTPHeaderFields = headers
                Alamofire.upload(multipartFormData: { (multipartFormData) in
            
                    multipartFormData.append(self.imageData_pf_pic, withName: "profile_image", fileName: "image.jpg", mimeType: "image/jpg")
            
            
                    for (key, value) in parameters {
            
                        multipartFormData.append((value as AnyObject).data(using: String.Encoding.utf8.rawValue)!, withName: key)
                    }
            
                }, with: urlRequest) { (encodingResult) in
            
                    switch encodingResult {
                    case .success(let upload, _, _):
                        upload.responseJSON { response in
                            if let JSON = response.result.value {
                                print("JSON: \(JSON)")
                                let status = (JSON as AnyObject).value(forKey: "status") as! Int
                                let sts = Int(status)
                                if sts == 200
                                {
                                    ApiUtillity.sharedInstance.dismissSVProgressHUD()
                                    let UserData = ((JSON as AnyObject).value(forKey: "data") as! NSDictionary)
                                    ApiUtillity.sharedInstance.setUserData(data: UserData)
            
            
                                }
                                else
                                {
                                    ApiUtillity.sharedInstance.dismissSVProgressHUD()
            
                                    let ErrorDic:NSDictionary = (JSON as AnyObject).value(forKey: "message") as! NSDictionary
            
                                    let Errormobile_no = ErrorDic.value(forKey: "mobile_no") as? String
                                    let Erroremail = ErrorDic.value(forKey: "email") as? String
            
                                    if Errormobile_no?.count == nil
                                    {}
                                    else
                                    {
                                        ApiUtillity.sharedInstance.dismissSVProgressHUDWithError(error: Errormobile_no!)
                                    }
                                    if Erroremail?.count == nil
                                    {}
                                    else
                                    {
                                        ApiUtillity.sharedInstance.dismissSVProgressHUDWithError(error: Erroremail!)
                                    }
                                }
            
                            }
            
                        }
            
                    case .failure(let encodingError):
                        ApiUtillity.sharedInstance.dismissSVProgressHUD()
                        print(encodingError)
                    }
            
                }
            }
            

            【讨论】:

            • 解释一下如何回答这个问题会很有帮助。
            • 当开发者想要使用alamofire传递图像数据和其他信息时是用户
            【解决方案10】:

            找到了另一种方法

             if let parameters = route.parameters {
            
                                for (key, value) in parameters {
                                     if value is String {
                                        if let temp = value as? String {
                                            multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
                                        }
                                    }
                                    else if value is NSArray {
                                        if let temp = value as? [Double]{
                                            multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
                                        }
                                        else if let temp = value as? [Int]{
                                            multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
                                        }
                                        else if let temp = value as? [String]{
                                            multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
                                        }
                                    }
                                    else if CFGetTypeID(value as CFTypeRef) == CFNumberGetTypeID() {
                                        if let temp = value as? Int {
                                            multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
                                        }
                                    }
                                    else if CFGetTypeID(value as CFTypeRef) == CFBooleanGetTypeID(){
                                        if let temp = value as? Bool {
                                            multipartFormData.append(temp.description.data(using: .utf8)!, withName: key)
                                        }
                                    }
                                }
                            }
            
                            if let items: [MultipartData] = route.multipartData{
                                for item in items {
                                    if let value = item.value{
                                        multipartFormData.append(value, withName: item.key, fileName: item.fileName, mimeType: item.mimeType)
                                    }
                                }
                            }
            

            【讨论】:

              【解决方案11】:

              Swift 5,将@Ankush 的Alamofire 代码更新为

                   var fullUrl = "http://httpbin.org/post" // for example
              
                         Alamofire.upload(multipartFormData: { (multipartFormData) in
                              multipartFormData.append( imagePathUrl! , withName: "photo")
                              multipartFormData.append( videoPathUrl!,  withName: "video")
                              multipartFormData.append(Constants.AuthKey.data(using: .utf8, allowLossyConversion: false)!, withName: "authKey")
                              multipartFormData.append("16".data(using: .utf8, allowLossyConversion: false)!, withName: "idUserChallenge")
                              multipartFormData.append("111".data(using: .utf8, allowLossyConversion: false)!, withName: "authKey")
                              multipartFormData.append("comment".data(using: .utf8, allowLossyConversion: false)!, withName: "comment")
                              multipartFormData.append("0.00".data(using: .utf8, allowLossyConversion: false)!, withName: "latitude")
                              multipartFormData.append("0.00".data(using: .utf8, allowLossyConversion: false)!, withName: "longitude")
                              multipartFormData.append("India".data(using: .utf8, allowLossyConversion: false)!, withName: "location")
              
                          }, to: fullUrl, method: .post) { (encodingResult) in
                              switch encodingResult {
                              case .success(request: let upload, streamingFromDisk: _, streamFileURL: _):
                                  upload.responseJSON { (response) in   // do sth     }
                              case .failure(let encodingError):
                                  ()
                              }
                          }
              

              【讨论】:

                【解决方案12】:

                Alamofire 5 及以上版本

                AF.upload(multipartFormData: { multipartFormData in
                    multipartFormData.append(Data("one".utf8), withName: "one")
                    multipartFormData.append(Data("two".utf8), withName: "two")
                }, 
                to: "https://httpbin.org/post").responseDecodable(of: MultipartResponse.self) { response in
                        debugPrint(response)
                }
                

                文档链接:multipart upload

                【讨论】:

                • 什么是 MultipartResponse ?
                猜你喜欢
                • 2020-04-14
                • 1970-01-01
                • 1970-01-01
                • 2019-08-11
                • 2021-02-06
                • 1970-01-01
                • 2017-12-17
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多