Alamofire: Comment gérer les erreurs globalement

Ma question est assez similaire à celle-ci, mais pour Alamofire: AFNetworking: gérer l'erreur globalement et répéter la requête

Comment être capable d'attraper globalement une erreur (typiquement un 401) et de la gérer avant que d'autres requests soient faites (et finalement échouées si elles ne sont pas gérées)?

Je pensais enstringr un gestionnaire de réponse personnalisé, mais c'est stupide de le faire à chaque request de l'application.
Peut-être sous-class, mais quelle class devrais-je sous-classr pour gérer cela?

La gestion de l'actualisation pour les réponses 401 dans un stream oauth est assez compliquée étant donné la nature parallèle des NSURLSessions. J'ai passé pas mal de time à développer une solution interne qui a très bien fonctionné pour nous. Ce qui suit est une extraction de très haut niveau de l'idée générale de la façon dont il a été mis en œuvre.

import Foundation import Alamofire public class AuthorizationManager: Manager { public typealias NetworkSuccessHandler = (AnyObject?) -> Void public typealias NetworkFailureHandler = (NSHTTPURLResponse?, AnyObject?, NSError) -> Void private typealias CachedTask = (NSHTTPURLResponse?, AnyObject?, NSError?) -> Void private var cachedTasks = Array<CachedTask>() private var isRefreshing = false public func startRequest( method method: Alamofire.Method, URLSsortingng: URLSsortingngConvertible, parameters: [Ssortingng: AnyObject]?, encoding: ParameterEncoding, success: NetworkSuccessHandler?, failure: NetworkFailureHandler?) -> Request? { let cachedTask: CachedTask = { [weak self] URLResponse, data, error in guard let strongSelf = self else { return } if let error = error { failure?(URLResponse, data, error) } else { strongSelf.startRequest( method: method, URLSsortingng: URLSsortingng, parameters: parameters, encoding: encoding, success: success, failure: failure ) } } if self.isRefreshing { self.cachedTasks.append(cachedTask) return nil } // Append your auth tokens here to your parameters let request = self.request(method, URLSsortingng, parameters: parameters, encoding: encoding) request.response { [weak self] request, response, data, error in guard let strongSelf = self else { return } if let response = response where response.statusCode == 401 { strongSelf.cachedTasks.append(cachedTask) strongSelf.refreshTokens() return } if let error = error { failure?(response, data, error) } else { success?(data) } } return request } func refreshTokens() { self.isRefreshing = true // Make the refresh call and run the following in the success closure to restart the cached tasks let cachedTaskCopy = self.cachedTasks self.cachedTasks.removeAll() cachedTaskCopy.map { $0(nil, nil, nil) } self.isRefreshing = false } } 

La chose la plus importante ici à retenir est que vous ne voulez pas lancer un appel d'actualisation pour chaque 401 qui revient. Un grand nombre de requests peuvent courir en même time. Par conséquent, vous souhaitez agir sur le premier 401, et mettre en queue toutes les requests supplémentaires jusqu'à ce que le 401 a réussi. La solution que j'ai décrite ci-dessus fait exactement cela. Toute tâche de données démarrée via la méthode startRequest sera automatiquement actualisée si elle atteint un 401.

Quelques autres choses importantes à noter ici qui ne sont pas sockets en count dans cet exemple très simplifié sont:

  • Fil-security
  • Succès garanti ou échec des appels de fermeture
  • Stocker et récupérer les jetons oauth
  • Analyser la réponse
  • Lancer la réponse analysée au type approprié (generics)

Espérons que cela aide à faire la lumière.


Mettre à jour

Nous avons maintenant publié 🔥🔥 Alamofire 4.0 🔥🔥 qui ajoute les protocoles RequestAdapter et RequestResortinger vous permettant de build facilement votre propre système d'authentification indépendamment des détails d'implémentation d'autorisation! Pour plus d'informations, veuillez vous reporter à notre file README qui contient un exemple complet de la façon dont vous pourriez implémenter le système OAuth2 dans votre application.

Divulgation complète: L'exemple dans le file README est uniquement destiné à être utilisé à titre d'exemple. S'il vous plaît s'il vous plaît s'il vous plaît ne pas simplement copyr et coller le code dans une application de production.