Alamofire 5,如何停止所有请求,刷新访问令牌并重新运行所有已停止的请求?

时间:2019-10-01 17:41:25

标签: swift alamofire ios13

我需要解决的情况-想象一下同时发出2个请求(当访问令牌无效时)。两者都尝试刷新令牌,但是其中之一会使另一令牌失效。

有什么方法可以做吗:

  1. 仅允许1刷新令牌
  2. 停止所有其他请求
  3. 重新运行所有已停止的请求(刷新令牌时)

还是您有其他解决方法的想法吗?

这是我的请求在每个视图控制器中的外观:

AF.request(encodedURLRequest, interceptor: AuthInterceptor()).validate().responseData { (response) in
    ...
}

这是我的AuthInterceptor:

final class AuthInterceptor: RequestInterceptor {

    func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
        var adaptedUrlRequest = urlRequest
        adaptedUrlRequest.setValue("Bearer \(UserDefaults.standard.getAccessToken())", forHTTPHeaderField: "Authorization")
        completion(.success(adaptedUrlRequest))
    }

    func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
        print("request \(request) failed")
        if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 403 {
            guard let url = URL(string: Endpoint.login.url) else { return }
            var urlRequest = URLRequest(url: url)
            urlRequest.httpMethod = "POST"
            urlRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

            let parameters: [String: String] = [
                "refresh_token": UserDefaults.standard.getRefreshToken(),
                "grant_type": "refresh_token"
            ]

            guard let encodedURLRequest = try? URLEncodedFormParameterEncoder.default.encode(parameters,
                                                                                             into: urlRequest) else { return }

            AF.request(encodedURLRequest).validate().responseData { (response) in
                if let data = response.data {
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase
                    if let loginResponse = try? decoder.decode(LoginResponse.self, from: data) {
                        UserDefaults.standard.setAccessToken(value: loginResponse.accessToken)
                        UserDefaults.standard.setRefreshToken(value: loginResponse.refreshToken)
                        completion(.retryWithDelay(1))
                    }
                }
            }
        }
    }

}

1 个答案:

答案 0 :(得分:0)

您可以使用Alamofire的RequestRetrier协议(作为RequestInterceptor协议的一部分)来执行此操作,而不必手动启动和停止请求。

本质上,您需要知道何时执行刷新,并存储由于令牌过期而失败的请求中的所有其他完成处理程序。您可以在AuthInterceptor类中执行此操作。只要确保您的实现是线程安全的!