在我的应用程序中,我正在使用Moya和RxSwift进行Web服务调用。这些调用是异步的,可以在新数据可用时由用户交互以及远程通知触发。
每个Web服务调用都需要在其 header 中进行身份验证。当用户更改密码时,将通过更改密码Web服务调用重新生成并返回 token 。
现在,当用户更改密码时,可能会发生远程通知并导致另一个Web服务调用。根据服务器的负载以及系统处理不同线程的方式,理论上可能发生以下情况:该调用是在另一个调用检索到新 token 之前,而服务器已经使旧 token 无效之后进行的。结果是HTTP 401未授权错误。
我想避免这种情况,但是我不确定最好的方法是什么,或者我的想法有误。
我发现此页面讨论锁,互斥锁和信号灯:https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html
似乎我应该这样使用“读写锁”:
到目前为止,这是正确的吗?接下来的一个大问题是:是否有更好的方法?在我开始更改所有Web服务调用之前:Moya或RxSwift中是否有内置机制可用于此目的?
最佳答案
我想分享一些关于 RxSwift 中的内置机制的想法。我认为有一些方法可以实现所需的行为。
The code below is just a theory and hasn't been tested. Please, don't cmd+c cmd+v this code. Its purpose is to show the simplified version of potential solution.
可以说我们有:
var activityIndicator = ActivityIndicator()
var relayToken = BehaviorRelay<String?>(value: nil)
其中
ActivityIndicator
是this struct,这有助于捕获多个Observables
的 Activity 。从理论上讲,请求方法将如下所示:
func request<D, P, R>(data: D, parameters: @escaping (D, String) -> P, response: @escaping (P) -> Observable<R>) -> Observable<R> {
return Observable
.just(data)
.flatMap({ (data: D) -> Observable<R> in
return relayToken
.asObservable()
.filterNil()
.take(1)
.map({ parameters(data, $0) })
.flatMap({ (parameters: P) -> Observable<R> in
return activityIndicator.trackActivity(response(parameters))
})
})
}
在哪里:
data: D
-初始请求参数parameters: @escaping (D, String) -> P
-将带有 token 的初始参数转换为完整请求参数的闭包。response: @escaping (P) -> Observable<R>
-将完整参数转换为正确请求Observable
的闭包。这是使用 Moya 或其他某种机制的地方。此函数等待单个有效 token 信号,并在接收到正确的 token 时将其转换为响应
Observable
,也由activityIndicator
跟踪。需要进行此类跟踪才能知道何时完成所有“读取”调用。结果-跟踪每个请求 Activity ,并且只有在收到有效 token 后,任何请求才会开始。
第二件事-仅在没有 Activity 请求时更改 token :
func update(token: String?) {
_ = Observable
.just(token)
.flatMap({ (token: String?) -> Observable<String?> in
return activityIndicator
.asObservable()
.filter({ $0 == false })
.take(1)
.map({ _ in token })
})
.bind(to: relayToken)
}
因此,无论何时决定更改 token ,都可以通过此功能应用其更改。它观察所有请求的 Activity ,并观察所有请求的 Activity -更改将被应用。
希望对您有所帮助,如有需要,请提问。
编辑1
“PATCH changePassword”可能不是正常请求之一,并且其 Activity 可能无法通过
activityIndicator
进行跟踪。relayToken = nil
。activityIndicator
将再次提供帮助)relayToken = some
因此,服务器将仅在所有已经启动的请求完成后使 token 无效。
我的解决方案阻止了以下所有新请求:
relayToken.asObservable().filterNil().take(1)
这意味着,虽然 token 是
nil
-等待。如果不是nil
,则只能进行一次。
关于ios - iOS Moya Web服务: make one call wait for all others to finish,然后阻止新调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48218770/