如何使用Alamofire重试请求?

时间:2019-04-22 13:52:14

标签: ios swift alamofire

如果第一个请求的响应代码为401,我可以在Alamofire中重新发送请求吗?在这里我可以刷新令牌并重试我的请求?

问题是我已经在使用MVVM和完成处理程序了。 在我的ViewModel中,请求函数如下所示:

public func getProfile(completion: @escaping (User?) -> Void) {
    guard let token = UserDefaults.standard.value(forKey: Constants.shared.tokenKey) else { return }

    let headers = ["Authorization": "Bearer \(token)"]

    URLCache.shared.removeAllCachedResponses()
    Alamofire.request(Constants.shared.getProfile, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers).responseJSON { (response) in
        switch response.result {
        case .success:
            guard let data = response.data else { return }

            if JSON(data)["code"].intValue == 401 {
                // here I need to refresh my token and re-send the request
            } else {
                let user = User(json: JSON(data)["data"])
                completion(user)
            }

            completion(nil)
        case .failure(let error):
            print("Failure, ", error.localizedDescription)
            completion(nil)
        }
    }
}

在ViewController中,我这样称呼它:

viewModel.getProfile { (user) in
    if let user = user {
        ...
    }
}

因此,我不知道如何在不使用新功能的情况下重试请求,因此仍然可以从ViewController的user部分获得completion响应。 也许有人可以告诉我正确的道路。 预先感谢!

3 个答案:

答案 0 :(得分:0)

如果接收到401,您是否可以递归调用该函数?您肯定需要创建某种类型的退出条件,以便如果它继续失败,它将崩溃,但是在我看来,它会起作用。

答案 1 :(得分:0)

是的,您可以使用Alamofire 4.0

  

RequestRetrier协议允许重试执行时遇到错误的请求。同时使用RequestAdapter和RequestRetrier协议时,可以为OAuth1,OAuth2,基本Auth甚至指数退避重试策略创建凭据刷新系统。可能性是无止境。这是一个示例,说明如何实现OAuth2访问令牌的刷新流程。

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, 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.requestsToRetry.forEach { $0(succeeded, 0.0) }
                strongSelf.requestsToRetry.removeAll()
            }
        }
    } else {
        completion(false, 0.0)
    }
}

参考:AlamofireDocumentation

答案 2 :(得分:0)

可以添加拦截器

Alamofire.request(Constants.shared.getProfile, method: .get, parameters: nil, encoding: URLEncoding.default, headers: headers)

添加协议RequestInterceptor

然后实现这两个协议方法

// retryCount number of time api need to retry

func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
   
    completion(.success(urlRequest))
}

func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
    guard request.retryCount < retryCount else {
        completion(.doNotRetry)
        return
    }
/// Call UR API here
}

一旦这两个方法调用 api 失败,就做