Alamofire: cómo manejar los errores a nivel mundial

Mi pregunta es bastante similar a esta, pero para Alamofire: AFNetworking: Maneje el error globalmente y repita la request

¿Cómo poder capturar un error globalmente (típicamente un 401) y manejarlo antes de que se realicen otras requestes (y eventualmente falladas si no se gestionan)?

Estaba pensando en encadenar un controller de respuesta personalizado, pero es una tontería hacerlo en cada request de la aplicación.
Tal vez subclass, pero ¿qué class debo subclass para manejar eso?

Manejar la actualización para 401 respuestas en un flujo de flujo es bastante complicado dada la naturaleza paralela de NSURLSessions. He pasado bastante time construyendo una solución interna que ha funcionado muy bien para nosotros. La siguiente es una extracción de muy alto nivel de la idea general de cómo se implementó.

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, URLString: URLStringConvertible, parameters: [String: 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, URLString: URLString, 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, URLString, 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 } } 

Lo más importante aquí para recordar es que no desea ejecutar una llamada de renovación por cada 401 que regrese. Una gran cantidad de requestes pueden competir al mismo time. Por lo tanto, desea actuar en el primer 401 y poner en queue todas las requestes adicionales hasta que el 401 haya tenido éxito. La solución que describí anteriormente hace exactamente eso. Cualquier tarea de datos que se inicie mediante el método startRequest se actualizará automáticamente si llega a un 401.

Algunas otras cosas importantes a tener en count aquí que no se explican en este ejemplo muy simplificado son:

  • Hilo de security
  • Llamadas de cierre garantizadas de éxito o fracaso
  • Almacenar y recuperar los tokens oauth
  • Analizando la respuesta
  • Lanzar la respuesta analizada al tipo apropiado (generics)

Espero que esto ayude a arrojar algo de luz.


Actualizar

Ahora hemos lanzado 🔥🔥 Alamofire 4.0 🔥🔥, que agrega los protocolos RequestAdapter y RequestRetrier , lo que le permite crear fácilmente su propio sistema de authentication, independientemente de los detalles de implementación de la autorización. Para get más información, consulte nuestro LÉAME que tiene un ejemplo completo de cómo podría implementar en el sistema OAuth2 en su aplicación.

Divulgación completa: el ejemplo en el README solo está destinado a utilizarse como ejemplo. Por favor, por favor, NO simplemente vaya y copie y pegue el código en una aplicación de producción.