ios - Alamofire : How to handle errors globally

标签 ios swift networking alamofire

我的问题与这个非常相似,但对于 Alamofire:AFNetworking: Handle error globally and repeat request

如何能够在全局范围内捕获错误(通常是 401)并在发出其他请求之前处理它(如果不加以管理,最终会失败)?

我曾考虑链接一个自定义响应处理程序,但在应用的每个请求上都这样做很愚蠢。
也许是子类化,但我应该子类化哪个类来处理它?<​​/p>

最佳答案

考虑到 NSURLSession 的并行性质,在 oauth 流程中处理 401 响应的刷新是相当复杂的。我花了相当多的时间来构建一个对我们来说非常有效的内部解决方案。以下是对其实现方式的总体思路的高度概括。

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 时自动刷新。

在此非常简化的示例中未考虑的其他一些需要注意的重要事项是:

  • 线程安全
  • 保证成功或失败的关闭调用
  • 存储和获取 oauth token
  • 解析响应
  • 将解析后的响应转换为适当的类型(泛型)

希望这有助于阐明一些问题。


更新

我们现已发布 🔥🔥 Alamofire 4.0 🔥🔥 添加了 RequestAdapterRequestRetrier 协议(protocol),让您可以轻松构建自己的身份验证系统,而无需考虑授权实现细节!更多信息,请引用我们的README其中有一个完整示例,说明如何在 OAuth2 系统上将其实现到您的应用中。

Full Disclosure: The example in the README is only meant to be used as an example. Please please please do NOT just go and copy-paste the code into a production application.

关于ios - Alamofire : How to handle errors globally,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28733256/

相关文章:

ios - 不能从标准主从模板中的 NSDate 更改

ios - Swift 3 添加新联系人电话和电子邮件信息

java - 如何让两台计算机用java相互通信以进行即时通讯?

ios - 圆形 UITableViewCell 仅底部或顶部角,但它不适用于 Swift iOS 10

ios - ShouldPerformSegue 触发两次

json - 使用 guard 语句从 json 解包到 AnyObject

json - 我如何使用 alamofire 解析 JSON

linux - 如何使用 iptables 将端口 80 限制为只有一个用户

javascript - 如何在 JavaScript 中记录获取的网络资源?

ios - Swift - UIPickerView - 使用 "reloadAllComponents"后组件仍然隐藏