web-dev-qa-db-fra.com

Envoyer POST des paramètres avec MultipartFormData utilisant Alamofire, dans iOS Swift

J'utilise Alamofire, pour la première fois. J'utilise la dernière version Alamofire 1.3.1. Je souhaite envoyer une image, une vidéo et certains paramètres POST dans un seul appel d'API. J'utilise des données de formulaire en plusieurs parties. Le module mutipart fonctionne. Je suis confronté à un problème pour envoyer des paramètres POST supplémentaires params. Ci-dessous mon code. "params" est le dictionnaire qui contient des paramètres supplémentaires? Comment puis-je ajouter ces paramètres POST dans la demande. S'il vous plaît aider

        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):

            }
        }
    )
44
Ankush

J'ai trouvé la solution :) enfin. 

Nous pouvons ajouter des données dans la demande sous la forme multipartformdata. 

Ci-dessous mon code.

  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):

            }
        }
    )

EDIT 1: Pour ceux qui essaient d'envoyer un tableau au lieu de float, int ou string, ils peuvent convertir leur tableau ou tout type de structure de données dans Json String, transmettez cette chaîne JSON sous forme de chaîne normale. Et analyser cette chaîne json en arrière-plan pour obtenir un tableau original

70
Ankush

Dans Alamofire 4, il est important d’ajouter les données du corps avant vous ajoutez les données du fichier!

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,
[...]
20
Alexander Scholz

Voici comment je résous mon problème

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)
        }


    }
17
Murat Akdeniz

Comme dans Swift 3.x pour télécharger une image avec un paramètre, nous pouvons utiliser ci-dessous la méthode de téléchargement 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)
            }

        }

    }

Remarque: De plus, si notre paramètre est un tableau de paires de clés, nous pouvons utilisation 

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

Pour 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)")
    }
}

Vous pouvez également jeter un oeil à CodyFire lib il facilite les appels d'API en utilisant Codable pour tout . Exemple pour un appel multipart utilisant 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{}

Vous pouvez consulter tous les exemples de le fichier readme } _

3
imike

Eh bien, étant donné que Multipart Form Data est destiné à être utilisé pour la transmission de données binaires (et pour le texte), je pense qu’il est une mauvaise pratique d’envoyer des données codées à String par dessus. 

Un autre inconvénient est l'impossibilité d'envoyer des paramètres plus complexes tels que JSON.

Cela dit, une meilleure option serait d’envoyer toutes les données sous forme binaire, c’est-à-dire en tant que données.

Dites que je dois envoyer ces données 

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

... à côté de la photo de l'utilisateur:

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

Pour cela, je convertirais ces données texte en JSON, puis en binaire à côté de l'image:

//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)

Et enfin, envoyez-le via la requête 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
        ...
    }
0
Arthur Shkil

pour alamofire 4, utilisez ceci ..

        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)

            }
        }
0
Subhojit Mandal