在请求发生之前更改Request
执行异步任务的正确方法是什么?
因此,任何请求Rn都需要透明地变为Tn,然后变成Rn。
此处有一些背景知识:该任务是一个第三方SDK,可分发我需要用作原始请求标头的令牌。
我的想法是装饰Rn,但是要做到这一点,我需要将Tn任务转换为Siesta Request
,然后才能进行链接。
因此,我包装了异步任务并将其链接到我的原始请求。
因此,任何Rn
都将变成Tn.chained { .passTo(Rn) }
这样,这种新行为对于整个应用程序是完全透明的。
问题
这样做,我的代码最终会在Siesta内部先决条件中崩溃:
precondition(completedValue == nil, "notifyOfCompletion() already called")
在我的自定义AsyncTaskRequest中,我收集成功,失败,进度等方面的回调,以便在SDK交付令牌时在主队列上触发它们。
我注意到,一旦执行所有删除的回调,崩溃就会消失,但是老实说,我没有找到原因。
我希望有足够的信息来提供一些提示或建议。 预先谢谢你。
答案 0 :(得分:1)
是的,实现Siesta的Request
界面绝非易事。其他人则有exactly the same problem-幸运的是Siesta版本1.4 includes a solution。
有关新功能的文档仍然很少。要使用新的API,您将实现新的RequestDelegate
协议,并将实现传递给Resource.prepareRequest(using:)
。这将返回一个您可以在标准Siesta请求链中使用的请求。结果将如下所示(警告-未经测试的代码):
struct MyTokenHandlerThingy: RequestDelegate {
// 3rd party SDK glue goes here
}
...
service.configure(…) {
if let authToken = self.authToken {
$0.headers["X-Auth-Token"] = authToken // authToken is an instance var or something
}
$0.decorateRequests {
self.refreshTokenOnAuthFailure(request: $1)
}
}
func refreshTokenOnAuthFailure(request: Request) -> Request {
return request.chained {
guard case .failure(let error) = $0.response, // Did request fail…
error.httpStatusCode == 401 else { // …because of expired token?
return .useThisResponse // If not, use the response we got.
}
return .passTo(
self.refreshAuthToken().chained { // If so, first request a new token, then:
if case .failure = $0.response { // If token request failed…
return .useThisResponse // …report that error.
} else {
return .passTo(request.repeated()) // We have a new token! Repeat the original request.
}
}
)
}
}
func refreshAuthToken() -> Request {
return Request.prepareRequest(using: MyTokenHandlerThingy())
.onSuccess {
self.authToken = $0.jsonDict["token"] as? String // Store the new token, then…
self.invalidateConfiguration() // …make future requests use it
}
}
}
要了解如何实现RequestDelegate
,目前最好的选择是查看new API docs directly in the code。
由于这是一个尚未发布的全新功能,非常感谢您提供有关该功能的工作原理以及遇到的任何麻烦的报告。