gpt4 book ai didi

cocoa - 如何在调用 API 之前使用 ReactiveCocoa 进行透明身份验证?

转载 作者:行者123 更新时间:2023-12-03 16:01:20 25 4
gpt4 key购买 nike

我在一个应用程序中使用 ReactiveCocoa,该应用程序调用远程 Web API。但在从给定 API 主机检索任何内容之前,应用程序必须提供用户的凭据并检索 API token ,然后使用该 token 对后续请求进行签名。

我想抽象出这个身份验证过程,以便每当我进行 API 调用时它就会自动发生。假设我有一个包含用户凭据的 API 客户端类。

// getThing returns RACSignal yielding the data returned by GET /thing.
// if the apiClient instance doesn't already have a token, it must
// retrieve one before calling GET /thing
RAC(self.thing) = [apiClient getThing];

如何使用 ReactiveCocoa 透明地导致对 API 的第一个(且仅第一个)请求进行检索,并作为副作用,在发出任何后续请求之前安全地存储 API token ?

还要求我可以使用 combineLatest: (或类似的)来启动多个并发请求,并且它们都将隐式等待检索 token 。

RAC(self.tupleOfThisAndThat) = [RACSignal combineLatest:@[ [apiClient getThis], [apiClient getThat]]];

此外,如果在进行 API 调用时检索 token 请求已在进行中,则该 API 调用必须等到检索 token 请求完成为止。

我的部分解决方案如下:

基本模式是使用 flattenMap: 将产生 token 的信号映射到给定 token 的信号,该信号执行所需的请求并产生 API 调用的结果。

假设对 NSURLRequest 进行一些方便的扩展:

- (RACSignal *)requestSignalWithURLRequest:(NSURLRequest *)urlRequest {
if ([urlRequest isSignedWithAToken])
return [self performURLRequest:urlRequest];

return [[self getToken] flattenMap:^ RACSignal * (id token) {
NSURLRequest *signedRequest = [urlRequest signedRequestWithToken:token];
assert([urlRequest isSignedWithAToken]);
return [self requestSignalWithURLRequest:signedRequest];
}
}

现在考虑 -getToken 的订阅实现。

  • 在简单的情况下,当已经检索到 token 时,订阅会立即生成 token 。
  • 如果尚未检索到 token ,订阅将推迟到返回 token 的身份验证 API 调用。
  • 如果身份验证 API 调用正在进行中,则可以安全地添加另一个观察者,而不会导致通过网络重复进行身份验证 API 调用。

但是我不知道该怎么做。另外,如何以及在哪里安全地存储 token ?某种持久/可重复的信号?

最佳答案

所以,这里发生了两件主要的事情:

  1. 您希望共享一些副作用(在本例中为获取 token ),而不是在每次有新订阅者时重新触发它们。
  2. 您希望订阅 -getToken 的任何人无论如何都能获得相同的值。

为了共享副作用(上面#1),我们将使用 RACMulticastConnection 。就像文档所说:

A multicast connection encapsulates the idea of sharing one subscription to a signal to many subscribers. This is most often needed if the subscription to the underlying signal involves side-effects or shouldn't be called more than once.

让我们将其中之一添加为 API 客户端类上的私有(private)属性:

@interface APIClient ()
@property (nonatomic, strong, readonly) RACMulticastConnection *tokenConnection;
@end

现在,这将解决 N 个当前订阅者都需要相同的 future 结果(API 调用正在等待请求 token 进行中)的情况,但我们仍然需要其他东西来确保 future 订阅者无论何时订阅,都会得到相同的结果(已获取的 token )。

这就是 RACReplaySubject用于:

A replay subject saves the values it is sent (up to its defined capacity) and resends those to new subscribers. It will also replay an error or completion.

为了将这两个概念联系在一起,我们可以使用 RACSignal's -multicast: method ,它通过使用特定类型的主题将正常信号转换为连接。

我们可以在初始化时连接大部分行为:

- (id)init {
self = [super init];
if (self == nil) return nil;

// Defer the invocation of -reallyGetToken until it's actually needed.
// The -defer: is only necessary if -reallyGetToken might kick off
// a request immediately.
RACSignal *deferredToken = [RACSignal defer:^{
return [self reallyGetToken];
}];

// Create a connection which only kicks off -reallyGetToken when
// -connect is invoked, shares the result with all subscribers, and
// pushes all results to a replay subject (so new subscribers get the
// retrieved value too).
_tokenConnection = [deferredToken multicast:[RACReplaySubject subject]];

return self;
}

然后,我们实现-getToken来触发延迟获取:

- (RACSignal *)getToken {
// Performs the actual fetch if it hasn't started yet.
[self.tokenConnection connect];

return self.tokenConnection.signal;
}

之后,任何订阅 -getToken 结果的内容(如 -requestSignalWithURLRequest:)都将获取 token (如果尚未获取),开始获取它如有必要,或者等待飞行中的请求(如果有)。

关于cocoa - 如何在调用 API 之前使用 ReactiveCocoa 进行透明身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14066651/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com