如何用异步任务装饰 Siesta 请求
How to decorate Siesta request with an asynchronous task
在请求发生之前更改 Request
执行异步任务的正确方法是什么?
所以任何请求Rn都需要透明化为Tn然后Rn。
这里有一些背景知识:任务是第 3 方 SDK,它发送一个令牌,我需要将其用作原始请求的 Header。
我的想法是装饰 Rn,但在这样做时我需要将我的 Tn 任务转换为 Siesta Request
然后我可以链接。
所以我包装了异步任务并链接到我的原始请求。
因此任何 Rn
都会变成 Tn.chained { .passTo(Rn) }
这样,这个新行为对整个应用程序来说是完全透明的。
问题
这样做我的代码最终会在 Siesta 内部前提条件下崩溃:
precondition(completedValue == nil, "notifyOfCompletion() already called")
在我的自定义 AsyncTaskRequest 中,我收集成功、失败、进度等的回调,以便在 SDK 交付令牌时在主 queue 上触发它们。
我注意到删除所有存储的回调一旦执行,崩溃就会消失,但老实说我没有找到原因。
我希望有足够的信息来提供一些提示或建议。
提前谢谢你。
是的,实现 Siesta 的 Request
接口绝非易事。其他人有 exactly the same problem — and luckily Siesta version 1.4 includes a solution.
新功能的文档仍然很薄。要使用新的 API,您将实现新的 RequestDelegate
协议,并将您的实现传递给 Resource.prepareRequest(using:)
。这将 return 一个您可以在标准 Siesta 请求链中使用的请求。结果看起来像这样(警告——未经测试的代码):
struct MyTokenHandlerThingy: RequestDelegate {
// 3rd party SDK glue goes here
}
...
service.configure(…) {
if let authToken = self.authToken {
[=10=].headers["X-Auth-Token"] = authToken // authToken is an instance var or something
}
[=10=].decorateRequests {
self.refreshTokenOnAuthFailure(request: )
}
}
func refreshTokenOnAuthFailure(request: Request) -> Request {
return request.chained {
guard case .failure(let error) = [=10=].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 = [=10=].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 = [=10=].jsonDict["token"] as? String // Store the new token, then…
self.invalidateConfiguration() // …make future requests use it
}
}
}
要了解如何实施 RequestDelegate
,目前最好的办法是查看 new API docs directly in the code。
由于这是一项尚未发布的全新功能,非常感谢您报告它的工作原理以及您遇到的任何问题。
在请求发生之前更改 Request
执行异步任务的正确方法是什么?
所以任何请求Rn都需要透明化为Tn然后Rn。
这里有一些背景知识:任务是第 3 方 SDK,它发送一个令牌,我需要将其用作原始请求的 Header。
我的想法是装饰 Rn,但在这样做时我需要将我的 Tn 任务转换为 Siesta Request
然后我可以链接。
所以我包装了异步任务并链接到我的原始请求。
因此任何 Rn
都会变成 Tn.chained { .passTo(Rn) }
这样,这个新行为对整个应用程序来说是完全透明的。
问题
这样做我的代码最终会在 Siesta 内部前提条件下崩溃:
precondition(completedValue == nil, "notifyOfCompletion() already called")
在我的自定义 AsyncTaskRequest 中,我收集成功、失败、进度等的回调,以便在 SDK 交付令牌时在主 queue 上触发它们。
我注意到删除所有存储的回调一旦执行,崩溃就会消失,但老实说我没有找到原因。
我希望有足够的信息来提供一些提示或建议。 提前谢谢你。
是的,实现 Siesta 的 Request
接口绝非易事。其他人有 exactly the same problem — and luckily Siesta version 1.4 includes a solution.
新功能的文档仍然很薄。要使用新的 API,您将实现新的 RequestDelegate
协议,并将您的实现传递给 Resource.prepareRequest(using:)
。这将 return 一个您可以在标准 Siesta 请求链中使用的请求。结果看起来像这样(警告——未经测试的代码):
struct MyTokenHandlerThingy: RequestDelegate {
// 3rd party SDK glue goes here
}
...
service.configure(…) {
if let authToken = self.authToken {
[=10=].headers["X-Auth-Token"] = authToken // authToken is an instance var or something
}
[=10=].decorateRequests {
self.refreshTokenOnAuthFailure(request: )
}
}
func refreshTokenOnAuthFailure(request: Request) -> Request {
return request.chained {
guard case .failure(let error) = [=10=].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 = [=10=].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 = [=10=].jsonDict["token"] as? String // Store the new token, then…
self.invalidateConfiguration() // …make future requests use it
}
}
}
要了解如何实施 RequestDelegate
,目前最好的办法是查看 new API docs directly in the code。
由于这是一项尚未发布的全新功能,非常感谢您报告它的工作原理以及您遇到的任何问题。