在请求发生之前更改执行异步任务的Request
的正确方法是什么?
因此,任何请求 Rn 都需要变得透明 Tn 然后 Rn。
这里有一些背景知识:该任务是一个第三方SDK,它调度了一个令牌,我需要将其用作原始请求的标头。
我的想法是装饰 Rn,但在这样做时,我需要将我的 Tn 任务转换为我可以链接的午睡Request
。
所以我包装了异步任务并链接到我的原始请求。 因此,任何Rn
都会变成Tn.chained { .passTo(Rn) }
这样,这种新行为对整个应用程序是完全透明的。
问题所在
这样做,我的代码最终会在 Siesta内部前提条件中崩溃:precondition(completedValue == nil, "notifyOfCompletion() already called")
在我的自定义 AsyncTaskRequest 中,我收集成功、失败、进度等回调,以便在 SDK 交付令牌时在主队列上触发它们。
我注意到一旦执行所有存储的回调,就会删除它们,崩溃就会消失,但老实说我没有找到原因。
我希望有足够的信息来提供一些提示或建议。 提前谢谢你。
是的,实现Siesta的Request
接口不是野餐。其他人也遇到了完全相同的问题 - 幸运的是,Siesta 1.4版本包含一个解决方案。
新功能的文档仍然很薄。要使用新的 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
,您现在最好的办法是直接在代码中查看新的 API 文档。
由于这是一项尚未发布的全新功能,因此非常感谢有关它如何为您工作以及您遇到的任何麻烦的报告。