公司的一个项目中的所有 API 接口无论是否登录都要带一个 token,如果没有 token 的话请求就会失败,因此在没有 token 或者是 token 失效的情况下要调用获取 token 的 API 将获取到的 token 存储到本地。
多次调用接口
写完代码后一测试,后台发现用户数量呈不正常的状态在增长,一查,发现每请求一次 token 都会生成一个用户。那么只能限制获取 token 的接口的调用次数了,一旦获取到 token,后续请求 token 的接口都取消。很自然地就想到用 OperationQueue 来做这个事情。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| private let operationQueue: OperationQueue = { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 return queue }() private let group = DispatchGroup() func getAccesstoken() { operationQueue.addOperation { [weak self] in guard let this = self else { return } this.getToken() } }
func getToken() { func handleResult(_ item: String) { operationQueue.cancelAllOperations() group.leave() }
func handleError(_ error: Error) -> Void { group.leave() }
group.enter()
webService.getToken() .done(handleResult) .catch(handleError) group.wait() }
|
这样就解决了多次调用获取 token 请求的问题。
Moya 重试请求
在 token 失效之后还得解决一个问题,那就是由于 token 失效导致的请求失败的问题,得让失败的请求进行重试,由于用的是 Moya 框架,搜索了许多重试的解决方案,无奈的是试过之后都不起作用,最后只能自己子类化一个 provider 来实现重试的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class CustomProvider<T: TargetType>: MoyaProvider<T> { @discardableResult override func request(_ target: T, callbackQueue: DispatchQueue? = .none, progress: ProgressBlock? = .none, completion: @escaping Completion) -> Cancellable { super.request(target, callbackQueue: callbackQueue, progress: progress) { result in switch result { case .success(let response): ... if statusCode == xxx { let queue = DispatchQueue(label: "com.network.retry", attributes: .concurrent) queue.asyncAfter(deadline: .now() + 3) { self.request(target, callbackQueue: callbackQueue, progress: progress, completion: completion) }
} else { completion(.success(response)) }
case .failure(let error): completion(.failure(error)) } } } }
|