如何用异步任务装饰 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

由于这是一项尚未发布的全新功能,非常感谢您报告它的工作原理以及您遇到的任何问题。