我使用ReactiveCocoa信号来表示对系统中RESTful后端的调用。每个RESTful调用都应该接收一个令牌作为参数之一。令牌本身是从认证API调用接收的。使用ReactiveCocoa重试异步操作
所有的工作都很好,现在我们引入了令牌过期,所以如果API调用失败并且HTTP代码为403,后端访问类可能需要重新授权。我想让调用者完全透明,这是最好的我想出了:
- (RACSignal *)apiCallWithSession:(Session *)session base:(NSString *)base params:(NSDictionary *)params get:(BOOL)get {
NSMutableDictionary* p = [params mutableCopy];
p[@"token"] = session.token;
RACSubject *subject = [RACReplaySubject subject];
RACSignal *first = [self apiCall:base params:p get:get]; // this returns the signal representing the asynchronous HTTP operation
@weakify(self);
[first subscribeNext:^(id x) {
[subject sendNext:x]; // if it works, all is fine
} error:^(NSError *error) {
@strongify(self);
// if it doesn't work, try re-requesting a token
RACSignal *f = [[self action:@"logon" email:session.user.email password:session.user.password]
flattenMap:^RACStream *(NSDictionary *json) { // and map it to the other instance of the original signal to proceed with new token
NSString *token = json[@"token"];
p[@"token"] = token;
session.token = token;
return [self apiCall:base params:p get:get];
}];
// all signal updates are forwarded, we're only re-requesting token once
[f subscribeNext:^(id x) {
[subject sendNext:x];
} error:^(NSError *error) {
[subject sendError:error];
} completed:^{
[subject sendCompleted];
}];
} completed:^{
[subject sendCompleted];
}];
return subject;
}
这是正确的方法吗?
感谢您的回答!除了'p'变量没有更新的事实,我看起来都很好。在我的代码片段中,调用'[self apiCall:params:get:]'两次调用*不同的*值'p'(第二次调用发生在更新后的令牌中)。在你的代码片段中,这可能会也可能不是这样(取决于代码的不同部分是否共享对象引用)。什么是使参数更新显式的好方法? –
'p'在上面的示例中以相同的方式更新。只要它是一个可变的字典,块就会看到更新。如果您想更明确一些,可以将'apiCall'变成一个代码块,其中包含''p'字典,然后_returns_用于API调用的'RACSignal'。 –
如果你想尝试获取令牌固定次数或重复直到它是正确的?我正在考虑你从用户那里获得凭据的情况,因此想要让用户有一两次机会来纠正或停止前进,直到他们做对了。 – Ayal