Alamofire:如何处理全球的错误

我的问题与这个非常相似,但对于Alamofire: AFNetworking:处理全局错误并重复请求

如何能够捕捉到全球性的错误(通常是401),并在其他请求之前处理(如果不pipe理,最终会失败)?

我正在考虑链接一个自定义的响应处理程序,但这是愚蠢的做到每个应用程序的请求。
也许inheritance,但我应该inheritance哪个类来处理?

鉴于NSURLSessions的并行性质,在oauthstream中处理401个响应的刷新相当复杂。 我花了相当长的时间build立一个内部解决scheme,对我们来说工作得非常好。 以下是关于如何实施的总体思路的非常高层次的提取。

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 } } 

这里要记住的最重要的事情是,你不想为每个返回的401执行刷新调用。 大量的请求可以在同一时间进行竞赛。 因此,您要在第一个401上执行操作,并将所有其他请求排队,直到401成功。 我上面概述的解决scheme正是如此。 任何通过startRequest方法启动的数据任务,如果遇到401,将自动刷新。

在这个非常简单的例子中没有说明的其他一些重要的事情是:

  • 线程安全
  • 保证成功或失败结束通话
  • 存储和获取oauth令牌
  • parsing响应
  • 将parsing的响应投射到适当的types(generics)

希望这有助于摆脱一些光。


更新

我们现在发布了Alamofire 4.0,它增加了RequestAdapterRequestRetrier协议,使您可以轻松构build自己的身份validation系统,而不pipe授权实现细节如何。 有关更多信息,请参阅我们的自述文件 ,其中有一个完整的示例,说明如何在OAuth2系统上实现您的应用程序。

完全披露:自述文件中的示例仅用作示例。 请请不要将代码复制粘贴到生产应用程序中。