2015-01-18 10 views
6

Ho un problema quando provo a inviare una richiesta POST alla mia API sul mio server, ho seguito molti tutorial diversi ma ancora non funziona. So che il mio problema è con la richiesta POST ma non riesco a risolverlo! Quindi questo è il mio codice in Swift e la mia API in php: (e sì ho sostituito xxxx dagli ID reali nel mio codice)POST con swift e API

Per riassumere il server ricevere la richiesta e ad esempio se inserisco manualmente un pseudo funziona, E 'davvero il metodo POST che non lavora .. il server non riceve il parametro POST

Swift code: codice

var request = NSMutableURLRequest(URL: NSURL(string: "http://localhost:8888/academy/test.php")!) 
    var session = NSURLSession.sharedSession() 
    request.HTTPMethod = "POST" 

    var params = ["pseudo":"test"] as Dictionary<String, String> 

    var err: NSError? 
    request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params, options: nil, error: &err) 
    request.addValue("application/json", forHTTPHeaderField: "Content-Type") 
    request.addValue("application/json", forHTTPHeaderField: "Accept") 

    var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in 
     println("Response: \(response)") 
     var strData = NSString(data: data, encoding: NSUTF8StringEncoding) 
     println("Body: \(strData)") 
     var err: NSError? 
     var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: &err) as? NSDictionary 

     // Did the JSONObjectWithData constructor return an error? If so, log the error to the console 
     if(err != nil) { 
      println(err!.localizedDescription) 
      let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding) 
      println("Error could not parse JSON: '\(jsonStr)'") 
     } 
     else { 
      // The JSONObjectWithData constructor didn't return an error. But, we should still 
      // check and make sure that json has a value using optional binding. 
      if let parseJSON = json { 
       // Okay, the parsedJSON is here, let's get the value for 'success' out of it 
       var success = parseJSON["success"] as? Int 
       println("Succes: \(success)") 
      } 
      else { 
       // Woa, okay the json object was nil, something went worng. Maybe the server isn't running? 
       let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding) 
       println("Error could not parse JSON: \(jsonStr)") 
      } 
     } 
    }) 
    task.resume()*/ 

PHP:

$BDD_hote = 'xxxxx'; 
$BDD_bd = 'xxxxx'; 
$BDD_utilisateur = 'xxxxx'; 
$BDD_mot_passe = 'xxxxx'; 

try{ 
$bdd = new PDO('mysql:host='.$BDD_hote.';dbname='.$BDD_bd, $BDD_utilisateur, $BDD_mot_passe); 
$bdd->exec("SET CHARACTER SET utf8"); 
$bdd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); 
} 

catch(PDOException $e){ 
echo 'Erreur : '.$e->getMessage(); 
echo 'N° : '.$e->getCode(); 
} 
$pseudo = addslashes($_POST["pseudo"]); 
$req = $bdd->query("SELECT * from users WHERE pseudo='$pseudo'"); 
$resultArray = array(); 
$donnees = $req->fetch(); 
echo json_encode($donnees); 

Grazie anticipatamente :)

+1

Si prega di dare un po 'più di dettaglio di "non funziona"? Dall'inizio e proseguendo, quale passaggio non ti dà il risultato atteso. Il server non ha ricevuto la richiesta? – kcome

+0

Quindi il server riceve la richiesta e ad esempio se inserisco manualmente una pseudo funziona, è davvero il metodo POST che non funziona .. Il server non riceve il parametro POST – sebasthug

+0

A proposito, punto minore, ma vedi la [documentazione di 'addSlashes'] (http://php.net/manual/en/function.addslashes.php) che consiglia di usare [' mysqli_real_escape_string'] (http://php.net/manual/en/mysqli .real-escape-string.php), invece. – Rob

risposta

11

Prova questo :

let myURL = NSURL(string: "http://localhost:8888/academy/test.php")! 
let request = NSMutableURLRequest(URL: myURL) 
request.HTTPMethod = "POST" 
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") 
request.setValue("application/json", forHTTPHeaderField: "Accept") 
let bodyStr:String = "pseudo=test" 
request.HTTPBody = bodyStr.dataUsingEncoding(NSUTF8StringEncoding) 
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { 
     data, response, error in 

     // Your completion handler code here 
} 
task.resume() 

È necessario codificare i dati utilizzando la codifica stringa UTF8. Se è necessario impostare più di un campo coppie di valori & per il corpo della richiesta, è possibile modificare la stringa del corpo, ad esempio "pseudo = test & language = swift". Infatti, di solito creo un'estensione per NSMutableURLRequest e aggiungo un metodo che prende un dizionario come parametro e imposta il contenuto di questa mappa (dizionario) come HTTPBody usando la codifica corretta. Questo può funzionare per voi:

extension NSMutableURLRequest { 
     func setBodyContent(contentMap: Dictionary<String, String>) { 
      var firstOneAdded = false 
      let contentKeys:Array<String> = Array(contentMap.keys) 
      for contentKey in contentKeys { 
       if(!firstOneAdded) { 
        contentBodyAsString += contentKey + "=" + contentMap[contentKey]! 
        firstOneAdded = true 
       } 
       else { 
        contentBodyAsString += "&" + contentKey + "=" + contentMap[contentKey]! 
       } 
      } 
      contentBodyAsString = contentBodyAsString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)! 
      self.HTTPBody = contentBodyAsString.dataUsingEncoding(NSUTF8StringEncoding) 
     } 
} 

ed è possibile utilizzare questo come:

request.setBodyContent(params) 

Spero che questo ti aiuta!

+1

Grazie mille per questo! =) – CodeMonkey

1

il seguente codice php è per ricevere il messaggio postale codificato application/url+encode. consultare https://en.wikipedia.org/wiki/Percent-encoding

$_POST["pseudo"] 

e il codice swift è stato l'invio di un JSON dati stringa codificata. Sono incompatibili.

Se non si desidera modificare il codice php, a Swift si dovrebbe inviare il messaggio formato URL-encode, li:

// aggiornato con le correzioni da @ Rob

var params = ["param1":"value1", "papam2": "value 2"] 
    var body = "" 
    for (key, value) in params { 
     body = body.stringByAppendingString(key) 
     body = body.stringByAppendingString("=") 
     body = body.stringByAppendingString(value.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!) 
     body = body.stringByAppendingString("&") 
    } 
    body = body.substringToIndex(advance(body.startIndex, countElements(body)-1)) // remove the last "&" 
    request.HTTPBody = body.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) 
+0

Ho provato ma non funziona:/Ma posso cambiare tutto (in PHP o Swift) non c'è alcun problema :) – sebasthug

+0

Mi dispiace non sono esperto in PHP, quindi da quello che ho capito in il tuo codice PHP, il problema è causato dal diverso formato dei dati tra invio e ricezione lato. – kcome

+0

Non dimenticare di cambiare 'Content-Type' nel mittente/Swift, imposta questo:' request.addValue ("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") 'non l'originale json uno. – kcome

15

Come altri hanno sottolineato, la codifica della richiesta non è corretta. Il tuo codice server non si aspetta la richiesta JSON, ma sta utilizzando le variabili $_POST (il che significa che la richiesta deve avere Content-Type di application/x-www-form-urlencoded). Quindi è quello che dovresti creare. Ad esempio, in Swift 3 e più tardi:

var request = URLRequest(url: url) 
request.httpMethod = "POST" 

let parameters = ["somekey" : "valueforkey"] 
request.setContent(with: parameters) 

let task = session.dataTask(with: request) { data, response, error in 
    guard let data = data, error == nil else { 
     print(error ?? "Unknown error") 
     return 
    } 
    // your response parsing code here 
} 
task.resume() 

Il metodo setContent vorrebbe un dizionario della forma ["key1": "foo", "key2" : "bar"] e popolare la httpBody con qualcosa che assomiglia key1=foo&key2=bar. Se lo fai, il server sarà in grado di analizzare lo $_POST dalla richiesta.

extension URLRequest { 
    /// Set body and header for x-www-form-urlencoded request 
    /// 
    /// - Parameter parameters: Simple string dictionary of parameters to be encoded in body of request 

    mutating func setContent(with parameters: [String: String]) { 
     setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") 

     let array = parameters.map { entry -> String in 
      let key = entry.key.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)! 
      let value = entry.value.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)! 
      return key + "=" + value 
     } 
     httpBody = array.joined(separator: "&").data(using: .utf8)! 
    } 
} 

nota, questo anche cento-codifica i valori (e, nel caso, le chiavi, troppo), che è critica. Mentre altri hanno consigliato l'uso di addingPercentEncoding con .urlQueryAllowed, purtroppo questo non farà il lavoro, in quanto permetterà ad alcuni caratteri riservati (in particolare +) di passare senza caratteri di escape. La maggior parte dei servizi Web interpreterà lo + come spazio, in conformità con the x-www-form-urlencoded spec. Quindi, adattando un approccio adottato da Alamofire, definisco un set di caratteri che si codificare i valori con i vari delimitatori:

extension CharacterSet { 

    /// Returns the character set for characters allowed in the individual parameters within a query URL component. 
    /// 
    /// The query component of a URL is the component immediately following a question mark (?). 
    /// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query 
    /// component is `key1=value1`. The individual parameters of that query would be the key `key1` 
    /// and its associated value `value1`. 
    /// 
    /// According to RFC 3986, the set of unreserved characters includes 
    /// 
    /// `ALPHA/DIGIT/"-"/"."/"_"/"~"` 
    /// 
    /// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters 
    /// for the sake of compatibility with some erroneous implementations, so this routine also allows those 
    /// to pass unescaped. 

    static var urlQueryValueAllowed: CharacterSet = { 
     let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 
     let subDelimitersToEncode = "!$&'()*+,;=" 

     var allowed = CharacterSet.urlQueryAllowed 
     allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode) 
     return allowed 
    }() 
} 

Per Swift 2 rendition, vedere previous revision of this answer.

+1

Ho qualche parametro ha carattere '+', continuamente in errore .... grazie finalmente capito :) –

+0

Grazie amico ... funziona bene – Sandu