web-dev-qa-db-fra.com

Gestion des erreurs dans Alamofire

J'ai le code HTTP dans un contrôleur AngularJS:

$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 = "";
    });

Dans le cas de réussite, le serveur répondra avec une représentation JSON d'un utilisateur. Dans le cas d'erreur, le serveur répondra avec une chaîne simple telle que User not found accessible par le paramètre data.

J'ai du mal à trouver comment faire quelque chose de similaire dans Alamofire. Voici ce que j'ai en ce moment:

@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"
                });
            }
    }
}

Je ne sais pas non plus si je gère correctement le cas sans erreur et j'apprécierais également une contribution à ce sujet.

15

Vous êtes sur la bonne voie, mais vous allez rencontrer des problèmes cruciaux avec votre implémentation actuelle. Il y a des choses Alamofire de bas niveau qui vont vous faire trébucher avec lesquelles je veux vous aider. Voici une version alternative de votre exemple de code qui sera beaucoup plus 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)")
            }
        }
    }
}

Validation

Tout d'abord, la fonction validate de la demande validera les éléments suivants:

  • HTTPStatusCode - Doit être 200 ... 299
  • Content-Type - Cet en-tête dans la réponse doit correspondre à l'en-tête Accept dans la demande d'origine

Vous pouvez trouver plus d'informations sur la validation dans Alamofire dans le readme .

Affaiblir/Fortifier

Assurez-vous de vous affaiblir et de vous affermir pour ne pas finir par créer un cycle de rétention.

Envoi vers la file d'attente principale

Vos appels de répartition vers la file d'attente principale ne sont pas nécessaires. Alamofire garantit que votre gestionnaire de complétion dans les sérialiseurs response et responseJSON est déjà appelé dans la file d'attente principale. Vous pouvez en fait fournir votre propre file d'attente de répartition pour exécuter les sérialiseurs si vous le souhaitez, mais ni votre solution ni la mienne ne le font actuellement, ce qui rend les appels de répartition vers la file d'attente principale complètement inutiles.

Sérialiseur de réponse

Dans votre cas particulier, vous ne voulez pas réellement utiliser le sérialiseur responseJSON. Si vous le faites, vous ne récupérerez aucune donnée si vous ne réussissez pas la validation. La raison en est que la réponse de la sérialisation JSON est ce qui sera renvoyé comme AnyObject. Si la sérialisation échoue, le AnyObject sera nul et vous ne pourrez pas lire les données.

Utilisez plutôt le sérialiseur response et essayez d'analyser les données manuellement avec NSJSONSerialization. Si cela échoue, vous pouvez compter sur la bonne méthode ole NSString(data:encoding:) pour imprimer les données.

J'espère que cela aidera à faire la lumière sur des moyens assez compliqués de se faire tromper.

28
cnoon

Alamofire traite donc toutes les demandes réussies. Cela revient vraiment aux en-têtes http du serveur API renvoyés.

Vous pouvez utiliser Alamofire.Request.validate ()

Cela vous permettra de valider les en-têtes http, etc. Consultez l'exemple

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

Je suppose que le message d'erreur sera dans l'objet data.

pour accéder aux valeurs des données, vous pourriez faire quelque chose comme

Je ne suis pas vraiment sûr de votre réponse api mais dans cet exemple

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