我的问题和这个很相似,但对于阿拉莫菲尔来说:AFNetworking: Handle error globally and repeat request
如何能够全局捕获错误(通常是401),并在发出其他请求之前处理它(如果不进行管理,最终会失败)?
我想链接一个自定义响应处理程序,但在应用程序的每个请求上都这样做是愚蠢的
我的问题和这个很相似,但对于阿拉莫菲尔来说:AFNetworking: Handle error globally and repeat request
如何能够全局捕获错误(通常是401),并在发出其他请求之前处理它(如果不进行管理,最终会失败)?
我想链接一个自定义响应处理程序,但在应用程序的每个请求上都这样做是愚蠢的
鉴于NSURLSessions的并行性质,在oauth流中处理401响应的刷新相当复杂.我花了相当长的时间构建了一个内部解决方案,它对我们非常有效.下面是对如何实现它的一般 idea 的一个非常高级的提取.
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成功.我上面概述的解决方案正是这样做的.通过startRequest
方法启动的任何数据任务,如果命中401,都会自动刷新.
在这个非常简单的例子中,需要注意的其他一些重要事项是:
希望这能帮助我们了解一些情况.
我们现在已经发布了?? 阿拉莫菲尔4.0?? 它添加了RequestAdapter
和RequestRetrier
协议,允许您轻松构建自己的身份验证系统,而不考虑授权实现细节!有关更多信息,请参阅我们的README,其中有一个完整的示例,说明如何在OAuth2系统上实现应用程序.
Full Disclosure:自述文件中的示例仅用作示例.请不要只是go 复制粘贴到生产应用程序的代码.