it-roy-ru.com

Послать POST параметры с MultipartFormData с использованием Alamofire, в iOS Swift

Я использую Alamofire, самый первый раз. Я использую последнюю версию Alamofire 1.3.1. Я хочу отправить одно изображение, одно видео и несколько параметров POST за один вызов API. Я использую данные из нескольких частей. Модуль mutipart работает. У меня проблема с отправкой дополнительных 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):

            }
        }
    )
44
Ankush

Я нашел решение :) наконец-то. 

Мы можем добавить данные в запрос как 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: Для тех, кто пытается отправить массив вместо float, int или string, они могут преобразовать свой массив или любую структуру данных в строку Json String, передайте эту строку JSON как обычную строку. И проанализировать эту строку JSON в бэкэнде, чтобы получить оригинальный массив

70
Ankush

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

Вот как я решаю свою проблему

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

Swift 3/Alamofire 4.0 _ ​​(Приложение к принятый ответ )

Чтобы добавить multipartFormData в Swift 3/Alamofire 4.0, используйте следующий метод MultipartFormData :

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

И, чтобы преобразовать String в Data, метод data(using:)String. Например.,

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

Как и в 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)
3
Jack

Для 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 это упрощает вызовы API, используя Codable для всего . Пример для многочастного вызова с использованием 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{}

Вы можете взглянуть на все примеры в libme readme

3
imike

Ну, поскольку Multipart Form Data предназначен для использования в двоичной (и для текстовой) передачи данных, я считаю плохой практикой отправлять данные в кодированном виде в 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:

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

для 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)

            }
        }
0
Subhojit Mandal