【问题标题】:Alamofire RequestRetrier with timeout error handling具有超时错误处理的 Alamofire RequestRetrier
【发布时间】:2017-06-01 09:00:12
【问题描述】:

我正在使用 RequestRetrier 为我的 API 自动更新 access_token。但是在每个请求函数中,我想捕获超时错误,但.responseJSON 正文中的.case(let error) 永远不会执行,因为(我猜)retrier 我添加到我的accessSessionManager 中。这是它的样子:

lazy var accessSessionManager: SessionManager = {
    let configuration = URLSessionConfiguration.default
    configuration.timeoutIntervalForRequest = Configuration.timeout
    configuration.timeoutIntervalForResource = Configuration.timeout
    let sessionManager = Alamofire.SessionManager(configuration: configuration)
    let oAuth2Handler = OAuth2Handler()
    sessionManager.retrier = oAuth2Handler
    sessionManager.adapter = oAuth2Handler
    return sessionManager
}()


func changeName(newName: String,completionHandler: ((_ success: Bool, _ error: String?) -> ())?) {
    guard let accessToken = self.getAccessToken() else { return }
    let parameters = ["access_token": accessToken,  "name": newName] as [String : Any]
    self.accessSessionManager.request(Constants.nameUrl, method: .get, parameters: parameters).responseJSON { response in
            switch response.result {
            case .success(let json):
                let jsonDict = JSON(json)
                if let success = jsonDict["success"].bool {
                    completionHandler?(success, nil)
                }

            case .failure(let error):
                if error._code == NSURLErrorTimedOut {
                    completionHandler?(false, "Please check your Internet connection and try again!")
                } else if response.response?.statusCode == 400 {
                    completionHandler?(false, "Sorry, name not found")
                } else if response.response?.statusCode != 401 {
                    completionHandler?(false, error.localizedDescription)
                }
            }
        }
    }
}

....
....
 class OAuth2Handler {

 //MARK: - Adapter
   func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
    if let url = urlRequest.url {
        guard let accessToken = self.getAccessToken() else { return  urlRequest }
        let newUrl = addOrUpdateQueryStringParameter(url: "\(url)", key: "access_token", value: accessToken)
        let newRequest = URLRequest(url: URL(string: newUrl)!)
        return newRequest
    }

    return urlRequest
}
 // MARK: - RequestRetrier
  func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
    lock.lock() ; defer { lock.unlock() }
    if let response = request.task?.response as? HTTPURLResponse {
        if response.statusCode == 401 {
            requestsToRetry.append(completion)
            if !isRefreshing {
                refreshTokens { [weak self] succeeded, accessToken, refreshToken in
                    guard let strongSelf = self else { return }
                    strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() }

                    if let accessToken = accessToken, let refreshToken = refreshToken {
                        strongSelf.accessToken = accessToken
                        strongSelf.refreshToken = refreshToken
                        strongSelf.updateAccessToken(accessToken: accessToken, refreshToken: refreshToken)
                    }
                    strongSelf.requestsToRetry.forEach { $0(succeeded, 0.0) }
                    strongSelf.requestsToRetry.removeAll()
                }
            }
        } else {
            completion(false, 0.0)
        }
    }
}

所以,基本上错误处理是在 should 函数中执行的,而不是在我的函数中的 .case(let error) 中。

【问题讨论】:

    标签: ios swift error-handling alamofire


    【解决方案1】:

    您没有验证您的请求。因此,它将让每个请求都成功。尝试通过在请求之后但响应之前添加 validate() 来验证您的请求:

    self.accessSessionManager.request(...).validate().responseJSON { ... }
    

    您可以找到自定义方法来更改 validate() 函数在其 readme 中接受和不接受的行为

    【讨论】:

    • 如果响应完成,它将成功,但是当我尝试捕获超时错误时,响应未完成,因此即使指定错误代码范围,添加 validate() 也无济于事。
    【解决方案2】:

    好的,这是我非常愚蠢的错误,如果error 发生在should 函数中,则基本上不会执行completion(false,0,0)。如果它看起来像这样,一切正常:

    // MARK: - RequestRetrier
    func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
    lock.lock() ; defer { lock.unlock() }
        if let response = request.task?.response as? HTTPURLResponse {
            if response.statusCode == 401 {
                requestsToRetry.append(completion)
                if !isRefreshing {
                    refreshTokens { [weak self] succeeded, accessToken, refreshToken in
                        guard let strongSelf = self else { return }
                        strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() }
    
                        if let accessToken = accessToken, let refreshToken = refreshToken {
                           strongSelf.accessToken = accessToken
                           strongSelf.refreshToken = refreshToken
                           strongSelf.updateAccessToken(accessToken: accessToken, refreshToken: refreshToken)
                       }
                       strongSelf.requestsToRetry.forEach { $0(succeeded, 0.0) }
                       strongSelf.requestsToRetry.removeAll()
                   }
                }
            } else {
               completion(false, 0.0)
        } else {
           completion(false,0.0)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-05
      • 2016-08-06
      • 2015-05-15
      • 2015-08-04
      • 2015-05-07
      • 2017-04-07
      • 2013-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多