Alamofire : How to handle errors globally

前端 未结 2 438
梦如初夏
梦如初夏 2020-12-07 08:14

My question is quite similar to this one, but for Alamofire : AFNetworking: Handle error globally and repeat request

How to be able to catch globally an error (typic

2条回答
  •  误落风尘
    2020-12-07 08:56

    Handling refresh for 401 responses in an oauth flow is quite complicated given the parallel nature of NSURLSessions. I have spent quite some time building an internal solution that has worked extremely well for us. The following is a very high level extraction of the general idea of how it was implemented.

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

    The most important thing here to remember is that you don't want to run a refresh call for every 401 that comes back. A large number of requests can be racing at the same time. Therefore, you want to act on the first 401, and queue all the additional requests until the 401 has succeeded. The solution I outlined above does exactly that. Any data task that is started through the startRequest method will automatically get refreshed if it hits a 401.

    Some other important things to note here that are not accounted for in this very simplified example are:

    • Thread-safety
    • Guaranteed success or failure closure calls
    • Storing and fetching the oauth tokens
    • Parsing the response
    • Casting the parsed response to the appropriate type (generics)

    Hopefully this helps shed some light.


    Update

    We have now released

提交回复
热议问题