2015-03-13 21 views
12

errore Ho il codice HTTP in un controller AngularJS:manipolazione in Alamofire

$http.post('/api/users/authenticate', {email: $scope.email, password: $scope.password}) 
    .success(function (data, status, headers, config) { 
     authService.login($scope.email); 
     $state.go('home'); 
    }) 
    .error(function (data, status, headers, config) { 
     $scope.errorMessages = data; 
     $scope.password = ""; 
    }); 

In caso di successo, il server risponderà con una rappresentazione JSON di un utente. Nel caso di errore il server risponderà con una semplice stringa come User not found a cui è possibile accedere tramite il parametro data.

Non riesco a capire come fare qualcosa di simile in Alamofire. Ecco quello che ho in questo momento:

@IBAction func LoginPressed(sender: AnyObject) { 
    let params: Dictionary<String,AnyObject> = ["email": emailField.text, "password": passwordField.text] 

    Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params) 
     .responseJSON {(request, response, data, error) in 
      if error == nil { 
       dispatch_async(dispatch_get_main_queue(), { 
        let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController; 

        self.presentViewController(welcome, animated: true, completion: nil); 
       }) 
      } 
      else{ 
       dispatch_async(dispatch_get_main_queue(), { 
        // I want to set the error label to the simple message which I know the server will return 
        self.errorLabel.text = "something went wrong" 
       }); 
      } 
    } 
} 

Non ho idea se sto occupando del caso non sia correttamente errore e gradirebbe input su quello.

risposta

26

Sei sono sulla strada giusta, ma si stanno per imbattersi in alcuni problemi cruciali con la tua attuale implementazione. Ci sono alcune cose di Alamofire di basso livello che ti faranno incavolare e con cui voglio aiutarti. Ecco una versione alternativa del tuo esempio di codice che sarà molto più efficace.

@IBAction func loginPressed(sender: AnyObject) { 
    let params: [String: AnyObject] = ["email": emailField.text, "password": passwordField.text] 

    let request = Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params) 
    request.validate() 
    request.response { [weak self] request, response, data, error in 
     if let strongSelf = self { 
      let data = data as? NSData 

      if data == nil { 
       println("Why didn't I get any data back?") 
       strongSelf.errorLabel.text = "something went wrong" 
       return 
      } else if let error = error { 
       let resultText = NSString(data: data!, encoding: NSUTF8StringEncoding) 
       println(resultText) 
       strongSelf.errorLabel.text = "something went wrong" 
       return 
      } 

      var serializationError: NSError? 

      if let json: AnyObject = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) { 
       println("JSON: \(json)") 
       let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController 
       self.presentViewController(welcome, animated: true, completion: nil) 
      } else { 
       println("Failed to serialize json: \(serializationError)") 
      } 
     } 
    } 
} 

convalida

Prima di tutto, la funzione validate sulla richiesta convaliderà la seguente:

  • HTTPStatusCode - deve essere di 200 ... 299
  • Content-Type - Questo l'intestazione nella risposta deve corrispondere all'intestazione Accept nella richiesta originale

È possibile trovare ulteriori informazioni sulla convalida in Alamofire nello README.

Weakify/Strongify

Assicurati di sé debole e forte auto vostra chiusura per essere sicuri di non finire la creazione di un ciclo di conservare.

Dispatch principale coda

tua spedizione richiama alla coda principale non sono necessari. Alamofire garantisce che il gestore di completamento nei serializzatori response e responseJSON sia già chiamato sulla coda principale. In realtà è possibile fornire la propria coda di invio per l'esecuzione dei serializzatori, se lo si desidera, ma né la propria soluzione né il mio lo stanno facendo in questo modo rendendo completamente inutili le chiamate di invio alla coda principale.

risposta Serializer

Nel vostro caso particolare, in realtà non vogliono utilizzare il responseJSON serializzatore. Se lo fai, non finirai per ricevere alcun dato se non superi la convalida. Il motivo è che la risposta dalla serializzazione JSON è ciò che verrà restituito come AnyObject. Se la serializzazione non riesce, il numero AnyObject sarà nullo e non sarà possibile leggere i dati.

Utilizzare invece il serializzatore response e provare a analizzare manualmente i dati con NSJSONSerialization. Se ciò non riesce, allora puoi fare affidamento sul buon metodo ole NSString(data:encoding:) per stampare i dati.

Speriamo che questo aiuti a far luce su alcuni modi abbastanza complicati per essere inciampato.

+0

Sta usando [auto debole] necessario quando non viene referenziato? Ho sempre capito che non è necessario se la chiusura non è fortemente referenziata da nessuna parte. – chourobin

+4

Ottima domanda, impossibile dare una risposta concisa a. Dipende dal comportamento che vuoi Se si desidera che il proprietario del metodo 'loginPressed' sia conservato in memoria, indipendentemente dal fatto che nient'altro abbia un riferimento ad esso, non si vorrebbe usare' [self debole] '. Tuttavia, si corre sempre il rischio potenziale di creare un ciclo di conservazione se non si utilizza il modello weakify/strongify. Maggiori informazioni [qui] (http://blackpixel.com/blog/2014/03/capturing-myself.html) e [qui] (http://stackoverflow.com/questions/24320347/shall-we-always-use -unowned-auto-inside-chiusura-in-veloce). – cnoon

+0

Buona spiegazione. In Swift 3 puoi sostituire 'if let strongSelf = self {...}' con solo 'guard let strongSelf = self else {return}' – Lion

1

Quindi Alamofire tratta tutte le richieste riuscite. Ciò dipende in realtà dalle intestazioni HTTP del server API restituite.

Si potrebbe utilizzare Alamofire.Request.validate()

Sarà consentono di convalidare le intestazioni HTTP, ecc check-out l'esempio

https://github.com/Alamofire/Alamofire#validation

Io parto dal presupposto il messaggio di errore sarà nell'oggetto data.

per accedere ai valori dai dati che si potrebbe fare qualcosa di simile

io non sono veramente sicuro di tuo aspetto di risposta API, ma in questo esempio

{ 
    "message": "Could not authenticate" 
} 
let message: String? = data?.valueForKey("message") as String 
+0

Giusto, tutto è considerato un successo. In un caso di errore il codice di stato potrebbe essere 500 e presumo che '' 'error''' non sia nullo. Quando questo è il caso, '' 'data''' è un' '' AnyObject''' e non sono sicuro di come accedere al contenuto '' 'User not found''. –