我正在使用https://github.com/p2/OAuth2通过OAuth2连接到我的应用程序的后端,效果很好。
我遇到的问题是,当访问令牌到期并且多个请求同时发生时,其中一些失败。
可以从应用程序的不同部分触发并行请求。例如,启动应用程序时,当前位置将发送到服务器,并下载事件列表。
确保第一个仍在运行时没有第二个刷新令牌请求的最佳方法是什么?
查找令牌寿命,并设置缓冲区(例如1-2分钟),如果令牌需要刷新,请在令牌刷新时保存所有请求。之后,执行所有保存的所有请求。您可以使用DispatchQueue和DispatchWorkItem进行此操作。
下面的示例代码。
final class Network: NSObject { static let shared = Network() private enum Constants { static let tokenRefreshDiffrenceMinute = 1 static let tokenExpireDateKey = "tokenExpireDate" } private(set) var tokenExpireDate: Date! { didSet { UserDefaults.standard.set(tokenExpireDate, forKey: Constants.tokenExpireDateKey) } } public override init() { super.init() if let date = UserDefaults.standard.object(forKey: Constants.tokenExpireDateKey) as? Date { tokenExpireDate = date print("Token found!") } else { print("Token not found!") isTokenRefreshing = true getToken { self.isTokenRefreshing = false self.executeAllSavedRequests() } } } private var isTokenRefreshing = false private var savedRequests: [DispatchWorkItem] = [] func request(url: String, params: [String: Any], result: @escaping (String?, Error?) -> Void) { // isTokenRefreshing save all requests if isTokenRefreshing { saveRequest { self.request(url: url, params: params, result: result) } return } // if token expire if getMinutesFrom2Dates(Date(), tokenExpireDate) < Constants.tokenRefreshDiffrenceMinute { // open this flag for we need wait refresh token isTokenRefreshing = true // save current request too saveRequest { self.request(url: url, params: params, result: result) } // get token self.getToken { [unowned self] in self.isTokenRefreshing = false self.executeAllSavedRequests() } } else { //Alamofire.request ... DispatchQueue.global().asyncAfter(deadline: .now() + 2) { DispatchQueue.main.async(execute: { result(url, nil) }) } } } private func saveRequest(_ block: @escaping () -> Void) { // Save request to DispatchWorkItem array savedRequests.append( DispatchWorkItem { block() }) } private func executeAllSavedRequests() { savedRequests.forEach({ DispatchQueue.global().async(execute: $0) }) savedRequests.removeAll() } private func getToken(completion: @escaping () -> Void) { print("Token needs a be refresh") // Goto server and update token DispatchQueue.global().asyncAfter(deadline: .now() + 1) { [unowned self] in DispatchQueue.main.async(execute: { [unowned self] in self.tokenExpireDate = Date().addingTimeInterval(120) print("Token refreshed!") completion() }) } } private func getMinutesFrom2Dates(_ date1: Date, _ date2: Date) -> Int { return Calendar.current.dateComponents([.minute], from: date1, to: date2).minute! } }