Comment faire une requête HTTP Post avec un corps JSON dans Swift


125

J'essaye de faire une demande de publication HTTP avec un corps JSON:

Comment pouvoir ajouter un NSdictionnary au corps de la requête HTTP.

Voici mon code, il ne semble pas fonctionner correctement.

var entry1 = Response(IdQuestion: 6510,IdProposition: 10,Time: 30)
var entry2 = Response(IdQuestion: 8284,IdProposition: 10,Time: 30)
Responses.append(entry1)
Responses.append(entry2)

let list = Responses.map { $0.asDictionary }

let json = ["List":list,"IdSurvey":"102","IdUser":"iOSclient","UserInformation":"iOSClient"]


let data : NSData = NSKeyedArchiver.archivedDataWithRootObject(json)


NSJSONSerialization.isValidJSONObject(json)

let myURL = NSURL(string: "http://www.myserver.com")!
let request = NSMutableURLRequest(URL: myURL)
request.HTTPMethod = "POST"


 request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.setValue("application/json", forHTTPHeaderField: "Accept")


request.HTTPBody = data
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
    data, response, error in
    println(response)
    // Your completion handler code here
}
task.resume()

Réponses:


214

Essaye ça,

// prepare json data
let json: [String: Any] = ["title": "ABC",
                           "dict": ["1":"First", "2":"Second"]]

let jsonData = try? JSONSerialization.data(withJSONObject: json)

// create post request
let url = URL(string: "http://httpbin.org/post")!
var request = URLRequest(url: url)
request.httpMethod = "POST"

// insert json data to the request
request.httpBody = jsonData

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else {
        print(error?.localizedDescription ?? "No data")
        return
    }
    let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
    if let responseJSON = responseJSON as? [String: Any] {
        print(responseJSON)
    }
}

task.resume()

ou essayez un moyen pratique Alamofire


1
très beau. version ajoutée avec la dernière syntaxe Swift (semble changer chaque semaine)
Fattie

1
@JoeBlow - veuillez publier votre alternative comme nouvelle réponse. C'est trop radicalement différent pour être une modification de celui-ci.
ChrisF

6
@JoeBlow - Je ne suis pas sûr qu'il y ait un consensus de la communauté à ce sujet, j'ai donc annulé à nouveau la modification et posé des questions à ce sujet sur Meta.SO: meta.stackoverflow.com/questions/339024/…
Brad Larson

2
Pour moi, l'ajout de cela a aidé: request.setValue("\(jsonData.length)", forHTTPHeaderField: "Content-Length") request.setValue("application/json", forHTTPHeaderField: "Content-Type") Réf
Mohammad Zaid Pathan

1
Ceci est dangereux à moins que vous pouvez également définir l' en- tête de type de contenu correctement: request.addValue("application/json", forHTTPHeaderField: "Content-Type"). Sinon, il fait le type pour les formulaires. La configuration très courante d'ExpressJS + bodyParser n'obtiendra que parfois des résultats incorrects , en fonction du contenu . Cela engendre donc des échecs silencieux.
sudo

46

HTTP Post dans Swift capturant les erreurs

let json = [ Activity.KEY_IDSUBJECT : activity.idSubject, Activity.KEY_RECORDMODE : "3", Activity.KEY_LOCATION_LONGITUDE : "0",Activity.KEY_LOCATION_LATITUDE : "0", Activity.KEY_CHECKIN : String(activity.dateCheckIn), Activity.KEY_CHECKOUT : String(activity.dateCheckOut) ]

do {
    let jsonData = try NSJSONSerialization.dataWithJSONObject(json, options: .PrettyPrinted)

    // create post request
    let url = NSURL(string: "https://...appspot.com/_ah/api/activityendpoint/v1/activity")!
    let request = NSMutableURLRequest(URL: url)
    request.HTTPMethod = "POST"

    // insert json data to the request
    request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.HTTPBody = jsonData


    let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
        if error != nil{
            print("Error -> \(error)")
            return
        }

        do {
            let result = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String:AnyObject]

            print("Result -> \(result)")

        } catch {
            print("Error -> \(error)")
        }
    }

    task.resume()
    return task
} catch {
    print(error)
}

est la demande d'envoi asynchrone
G.Abhisek

1
@Logan la documentation dit que dataTaskWithRequest fournit "une interface asynchrone annulable simple pour recevoir des données". Je suppose donc que cet appel est déjà asynchrone sans dispatch_async
David Schumann

46

Swift 4 et 5

HTTP POST requestutilisation URLSession APIdans Swift 4

func postRequest(username: String, password: String, completion: @escaping ([String: Any]?, Error?) -> Void) {

    //declare parameter as a dictionary which contains string as key and value combination.
    let parameters = ["name": username, "password": password]

    //create the url with NSURL
    let url = URL(string: "https://www.myserver.com/api/login")!

    //create the session object
    let session = URLSession.shared

    //now create the Request object using the url object
    var request = URLRequest(url: url)
    request.httpMethod = "POST" //set http method as POST

    do {
        request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to data object and set it as request body
    } catch let error {
        print(error.localizedDescription)
        completion(nil, error)
    }

    //HTTP Headers
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    //create dataTask using the session object to send data to the server
    let task = session.dataTask(with: request, completionHandler: { data, response, error in

        guard error == nil else {
            completion(nil, error)
            return
        }

        guard let data = data else {
            completion(nil, NSError(domain: "dataNilError", code: -100001, userInfo: nil))
            return
        }

        do {
            //create json object from data
            guard let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else {
                completion(nil, NSError(domain: "invalidJSONTypeError", code: -100009, userInfo: nil))
                return
            }
            print(json)
            completion(json, nil)
        } catch let error {
            print(error.localizedDescription)
            completion(nil, error)
        }
    })

    task.resume()
}

@objc func submitAction(_ sender: UIButton) {
    //call postRequest with username and password parameters
    postRequest(username: "username", password: "password") { (result, error) in
    if let result = result {
        print("success: \(result)")
    } else if let error = error {
        print("error: \(error.localizedDescription)")
    }
}

Utilisation d'Alamofire:

let parameters = ["name": "username", "password": "password123"]
Alamofire.request("https://www.myserver.com/api/login", method: .post, parameters: parameters, encoding: URLEncoding.httpBody)

Cherchait ce "URLEncoding.httpBody" pendant un moment, merci
Tiago Mendes

10

Le code Swift 5 Playground suivant montre un moyen possible de résoudre votre problème en utilisant JSONSerializationet URLSession:

import UIKit
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

let url = URL(string: "http://localhost:8080/new")!
let jsonDict = ["firstName": "Jane", "lastName": "Doe"]
let jsonData = try! JSONSerialization.data(withJSONObject: jsonDict, options: [])

var request = URLRequest(url: url)
request.httpMethod = "post"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = jsonData

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
    if let error = error {
        print("error:", error)
        return
    }

    do {
        guard let data = data else { return }
        guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject] else { return }
        print("json:", json)
    } catch {
        print("error:", error)
    }
}

task.resume()

Spécifier "application / json" comme ContentType est très important. sinon, la requête sera exécutée comme le formulaire HTTP habituel. Bonne réponse.
heximal

5
let url = URL(string: "url")!
var request = URLRequest(url: url)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")

request.httpMethod = "POST"



let postString = "ChangeAccordingtoyourdata=\(paramOne)&ChangeAccordingtoyourdata2=\(paramTwo)"
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else {                                                 // check for fundamental networking error
        print("error=\(error)")
        return
    }

    if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           // check for http errors
        print("statusCode should be 200, but is \(httpStatus.statusCode)")
        print("response = \(response)")

        SVProgressHUD.showError(withStatus: "Request has not submitted successfully.\nPlease try after some time")
    }

    let responseString = String(data: data, encoding: .utf8)
    print("responseString = \(responseString)")

    SVProgressHUD.showSuccess(withStatus: "Request has submitted successfully.\nPlease wait for a while")
    DispatchQueue.main.async {



    // enter code

    }

}
task.resume()

4

Réponse parfaite de nRewik mise à jour en 2019:

Faites le dictionnaire:

let dic = [
    "username":u,
    "password":p,
    "gems":g ]

Assemblez-le comme ceci:

var jsonData:Data?
do {
    jsonData = try JSONSerialization.data(
      withJSONObject: dic,
      options: .prettyPrinted)
} catch {
    print(error.localizedDescription)
}

Créez la demande exactement comme ceci, notez qu'il s'agit d'un "post"

let url = URL(string: "https://blah.com/server/dudes/decide/this")!
var request = URLRequest(url: url)

request.setValue("application/json; charset=utf-8",
     forHTTPHeaderField: "Content-Type")
request.setValue("application/json; charset=utf-8",
     forHTTPHeaderField: "Accept") 
request.httpMethod = "POST"
request.httpBody = jsonData

Ensuite, envoyez, en recherchant une erreur de réseau (donc, pas de bande passante, etc.) ou une réponse d'erreur du serveur:

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    guard let data = data, error == nil else {
        // check for fundamental networking error
        print("fundamental networking error=\(error)")
        return
    }

    if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
        // check for http errors
        print("statusCode should be 200, but is \(httpStatus.statusCode)")
        print("response = \(response)")
    }

    let responseString = String(data: data, encoding: .utf8)
    print("responseString = \(responseString)")

Heureusement, c'est maintenant aussi simple.


3

vous pouvez faire quelque chose comme ceci:

func HTTPPostJSON(url: String,  data: NSData,
    callback: (String, String?) -> Void) {

        var request = NSMutableURLRequest(URL: NSURL(string: url)!)
        request.HTTPMethod = "POST"
        request.addValue("application/json",forHTTPHeaderField: "Content-Type")
        request.addValue("application/json",forHTTPHeaderField: "Accept")
        request.HTTPBody = data
        HTTPsendRequest(request, callback: callback)
}

func HTTPsendRequest(request: NSMutableURLRequest,
    callback: (String, String?) -> Void) {
        let task = NSURLSession.sharedSession()
            .dataTaskWithRequest(request) {
                (data, response, error) -> Void in
                if (error != nil) {
                    callback("", error.localizedDescription)
                } else {
                    callback(NSString(data: data,
                        encoding: NSUTF8StringEncoding)! as String, nil)
                }
        }

        task.resume()
}
//use
var data :Dictionary<String, AnyObject> = yourDictionaryData<--
var requestNSData:NSData = NSJSONSerialization.dataWithJSONObject(request, options:NSJSONWritingOptions(0), error: &err)!
HTTPPostJSON("http://yourPosturl..", data: requestNSData) { (response, error) -> Void in
    if error != nil{
        //error
        return;
    }

    println(response);
}

3

SWIFT 5 personnes ici:

let json: [String: Any] = ["key": "value"]

        let jsonData = try? JSONSerialization.data(withJSONObject: json)

        // create post request
        let url = URL(string: "http://localhost:1337/postrequest/addData")! //PUT Your URL
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("\(String(describing: jsonData?.count))", forHTTPHeaderField: "Content-Length")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        // insert json data to the request
        request.httpBody = jsonData

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil else {
                print(error?.localizedDescription ?? "No data")
                return
            }
            let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
            if let responseJSON = responseJSON as? [String: Any] {
                print(responseJSON) //Code after Successfull POST Request
            }
        }

        task.resume()

Bonne réponse. Cela a fonctionné dans un mode copier-coller pour moi.
podcastfan88

1
var request = URLRequest(url: URL(string: "http://yogpande.apphb.com/api/my/posttblhouse")!)
        request.httpMethod = "POST"
        let postString = "email=testname@gmail.com&password=1234567"
        request.httpBody = postString.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil else {
                print("error=(error)")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {     
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(response)")

            }

            let responseString = String(data: data, encoding: .utf8)
            print("responseString = \(responseString)")
        }
        task.resume()
    }

1

Swift4 - Solution Apple "POST" et "Codable"

Téléchargement de données sur un site Web à l'aide de request.httpmethod = "Post" et Codable Stucts :

@see: Listing 2 Configurer une requête URL

let userlogin = User(username: username, password: password, deviceid:UIDevice.current.identifierForVendor!.uuidString)

    guard let uploadData = try? JSONEncoder().encode(userlogin) else {
        print("Error UploadData: ")
        return
    }

    let urlUser = URL(string: APPURL.apiURL)!

    var request = URLRequest(url: urlUser)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")

    var responseStatus = 0

    let task = URLSession.shared.uploadTask(with: request, from: uploadData) { data, response, error in
        if let error = error {
            let code = (error as NSError).code
            print("Error:\(code) : \(error.localizedDescription)")
            completion(code)
            return
        }  
      guard let response = response as? HTTPURLResponse else {
            print("Invalid response")
            return
        }
// do your response handling here ...

Cette réponse n'était pas vraiment bonne - cependant, le lien contenait du code utilisable récent. 😃
Jonny

@Jonny: C'est juste la configuration minimale pour obtenir un POST, mais vous avez raison, il manque la partie codable ... ma faute! J'ai mis à jour cela maintenant.
andreas-supersmart

Oui Structs codable est le futur 🚀
Jonny

salut! J'ai trouvé cette réponse, mais ne peut pas l' utiliser pour résoudre ma question, pourrait aider quelqu'un me ici ?: stackoverflow.com/questions/53598917/...
biggreentree

1
    // prepare json data
    let mapDict = [ "1":"First", "2":"Second"]

    let json = [ "title":"ABC" , "dict": mapDict ] as [String : Any]
    let jsonData : NSData = NSKeyedArchiver.archivedData(withRootObject: json) as NSData

    // create post request
    let url = NSURL(string: "http://httpbin.org/post")!
    let request = NSMutableURLRequest(url: url as URL)
    request.httpMethod = "POST"

    // insert json data to the request
    request.httpBody = jsonData as Data


    let task = URLSession.shared.dataTask(with: request as URLRequest){ data,response,error in
        if error != nil{
            return
        }
        do {
            let result = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]

            print("Result",result!)

        } catch {
            print("Error -> \(error)")
        }
    }

    task.resume()

0
    var request = URLRequest(url: URL(string:  "your URL")!)
    request.httpMethod = "POST"


    let postString =  String(format: "email=%@&lang=%@", arguments: [txt_emailVirify.text!, language!])
    print(postString)

    emailString = txt_emailVirify.text!

    request.httpBody = postString.data(using: .utf8)
    request.addValue("delta141forceSEAL8PARA9MARCOSBRAHMOS", forHTTPHeaderField: "Authorization")
    request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")


    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil
            else
        {
            print("error=\(String(describing: error))")
            return
        }

        do
        {

            let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! NSDictionary
            print(dictionary)

            let status = dictionary.value(forKey: "status") as! String
            let sts = Int(status)
            DispatchQueue.main.async()
                {
                    if sts == 200
                    {
                        print(dictionary)


                    }
                    else
                    {
                       self.alertMessageOk(title: self.Alert!, message: dictionary.value(forKey: "message") as! String)


                    }
            }
        }
        catch
        {
            print(error)
        }

    }
    task.resume()

0
func fucntion()
{

    var parameters = [String:String]()
    let apiToken = "Bearer \(ApiUtillity.sharedInstance.getUserData(key: "vAuthToken"))"
    let headers = ["Vauthtoken":apiToken]

    parameters = ["firstname":name,"lastname":last_name,"mobile":mobile_number,"email":emails_Address]


    Alamofire.request(ApiUtillity.sharedInstance.API(Join: "user/edit_profile"), method: .post, parameters: parameters, encoding: URLEncoding.default,headers:headers).responseJSON { response in
        debugPrint(response)
        if let json = response.result.value {
            let dict:NSDictionary = (json as? NSDictionary)!
            print(dict)
            //                print(response)

            let StatusCode = dict.value(forKey: "status") as! Int

            if StatusCode==200
            {
                ApiUtillity.sharedInstance.dismissSVProgressHUDWithSuccess(success: "Success")
                let UserData = dict.value(forKey: "data") as! NSDictionary
                print(UserData)

            }

            else if StatusCode==401
            {
                let ErrorDic:NSDictionary = dict.value(forKey: "message") as! NSDictionary
                let ErrorMessage = ErrorDic.value(forKey: "error") as! String

            }
            else
            {

                let ErrorDic:NSDictionary = dict.value(forKey: "message") as! NSDictionary
                let ErrorMessage = ErrorDic.value(forKey: "error") as! String
            }

        }
        else
        {
            ApiUtillity.sharedInstance.dismissSVProgressHUDWithError(error: "Something went wrong")
        }
    }

0

une combinaison de plusieurs réponses trouvées dans ma tentative de ne pas utiliser de frameworks tiers comme Alamofire.

    let body: [String: Any] = ["provider": "Google", "email": "emailaddress@gmail.com"]
    let api_url = "https://erics.es/p/u"
    let url = URL(string: api_url)!
    var request = URLRequest(url: url)

    do {
        let jsonData = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
        request.httpBody = jsonData
    } catch let e {
        print(e)
    }

    request.httpMethod = HTTPMethod.post.rawValue
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")

    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        guard let data = data, error == nil else {
            print(error?.localizedDescription ?? "No data")
            return
        }
        let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
        if let responseJSON = responseJSON as? [String: Any] {
            print(responseJSON)
        }
    }

    task.resume()

0
import UIKit

class ViewController: UIViewController {

    var getdata = NSMutableData()
    @IBOutlet weak var password_txt: UITextField!
    @IBOutlet weak var mobile_txt: UITextField!
    @IBOutlet weak var email_txt: UITextField!
    @IBOutlet weak var name_txt: UITextField!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.

    }
    @IBAction func RegAction(_ sender: UIButton) {
        let url = URL(string: "https//.....")
        var requrl = URLRequest(url: url!)
        requrl.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "content_type")
        requrl.httpMethod = "post"
        let postString = "name=\(name_txt.text!)&email=\(email_txt.text!)&mobile=\(mobile_txt.text!)&password=\(password_txt.text!)"
        print("poststring-->>",postString)
        requrl.httpBody = postString.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: requrl){(data,response,error) in
            let mydata = data
            do{
                print("mydata",mydata!)
                do{
                    self.getdata.append(mydata!)
                    let jsondata = try JSONSerialization.jsonObject(with: self.getdata as Data, options: [])
                    print("jsondata-->",jsondata)
                }
            }
            catch
            {
                print("error-->",error.localizedDescription)
            }
        };
        task.resume()

    }
}
`GET METHOD`
import UIKit

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
    var dataarray = [[String: Any]]()
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataarray.count
    }
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 450.0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
        let  item = dataarray[indexPath.row]

        cell.name_txt.text = item["name"]as? String ?? ""
        cell.pname_txt.text = item["realname"]as? String ?? ""
        cell.team_txt.text = item["team"]as? String ?? ""
        cell.firstapp_txt.text = item["firstappearance"]as? String ?? ""
        cell.Createdby_txt.text = item["createdby"]as? String ?? ""
        cell.Publisher_txt.text = item["publisher"]as? String ?? ""

        if item["imageurl"]as? String ?? "" != ""{
            let url = URL(string: item["imageurl"]as? String ?? "")
            if url != nil{
                let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
                cell.imgvw.image = UIImage(data: data!)
            }
        }
        return cell
     }


    @IBOutlet weak var apiTable: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
    override func viewWillAppear(_ animated: Bool) {
        guard let url = URL(string: "https://www.simplifiedcoding.net/demos/marvel/")
            else {return}
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let dataResponse = data,
                error == nil else {
                    print(error?.localizedDescription ?? "Response Error")
                    return }
            do{
                //here dataResponse received from a network request
                let jsonResponse = try JSONSerialization.jsonObject(with:
                    dataResponse, options: []) as? [[String:Any]] ?? [[:]]
                print("jsonResponse---->",jsonResponse) //Response result

                self.dataarray = jsonResponse
                DispatchQueue.main.async {



                    self.apiTable.reloadData()
                }
            } catch let parsingError {
                print("Error", parsingError)
            }
        }
        task.resume()
    }

}

Il est préférable d'inclure une description de votre problème plutôt que de simplement coller le code.
Calos le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.