iOS-重新尝试NSURLSession中的NSURLRequests失败
在我的应用程序中,对我的服务器的2-4个API调用可以在我的API类的iOS-重新尝试NSURLSession中的NSURLRequests失败,ios,api,authentication,nsurlsession,nsurlrequest,Ios,Api,Authentication,Nsurlsession,Nsurlrequest,在我的应用程序中,对我的服务器的2-4个API调用可以在我的API类的NSURLSession中同时(异步)发生。为了向我的服务器发出API请求,我必须在每个NSURLRequest的HTTPHeaderField中提供身份验证令牌。令牌有效期为一天,如果一天之后无效,我需要刷新令牌 我在API类中的以下代码中执行此操作: /*! * @brief sends a request as an NSHTTPURLResponse. This method is private. * @para
NSURLSession
中同时(异步)发生。为了向我的服务器发出API请求,我必须在每个NSURLRequest
的HTTPHeaderField
中提供身份验证令牌。令牌有效期为一天,如果一天之后无效,我需要刷新令牌
我在API类中的以下代码中执行此操作:
/*!
* @brief sends a request as an NSHTTPURLResponse. This method is private.
* @param request The request to send.
* @param success A block to be called if the request is successful.
* @param error A block to be called if the request fails.
*/
-(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback
{
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
[self parseResponse:response data:data fromRequest:request successCallback:success errorCallback:^(NSString *error)
{
//if auth token expired and getting "not authenticated" error (status 401)
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 401) {
[self refreshAuthenticationTokenWithSuccessCallback:^(NSDictionary *response) {
self.authToken = response[@"token"];
//attempt to re-try the request that failed due to token expiration
[self sendTask:request successCallback:success errorCallback:errorCallback];
} errorCallback:^(NSString *error) {
//two weeks have passed and the token is no longer refreshable
NSLog(@"TOKEN NOT REFRESHABLE! HAVE TO LOG IN MANUALLY");
}];
}
}];
}];
[task resume];
}
这个sendTask
方法会在我在应用程序中发出的每个API请求中执行,所以我才意识到这是一种不好的方法。如果3个API请求由于令牌无效而失败(一天过去了),那么所有3个API请求都将尝试进行API调用以刷新身份验证令牌
如果其中一个API请求失败,是否有办法只刷新一次身份验证令牌,然后重新尝试失败的API调用
编辑
我编辑了问题的标题,以表明我正在使用NSURLSession
进步
到目前为止,为了防止多个失败的API请求同时尝试刷新身份验证令牌,我为所有失败的请求提供了一个NSArray
,还有一个NSNumber
,用作锁,以确保身份验证令牌只尝试刷新一次。我使用以下代码执行此操作:
-(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback
{
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
MyAPIInterface *__weak weakSelf = self;
[self parseResponse:response data:data fromRequest:request successCallback:success errorCallback:^(NSString *error)
{
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 401) {
if ([error isEqualToString:@"invalid_credentials"]) {
errorCallback(@"Invalid username and/or password");
}
else if ([error isEqualToString:@"Unknown error"]) {
errorCallback(error);
}
else {
if (!weakSelf.alreadyRefreshingToken.boolValue) {
//lock alreadyRefreshingToken boolean
weakSelf.alreadyRefreshingToken = [NSNumber numberWithBool:YES];
NSLog(@"NOT REFRESHING TOKEN");
// add failed request to failedRequests array
NSMutableArray *mutableFailedRequests = [weakSelf.failedRequests mutableCopy];
[mutableFailedRequests addObject:request];
weakSelf.failedRequests = [mutableFailedRequests copy];
// refresh auth token
[weakSelf refreshAuthenticationTokenWithSuccessCallback:^(NSDictionary *response) {
//store authToken
weakSelf.authToken = response[@"token"];
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:weakSelf.authToken forKey:@"authToken"];
[defaults synchronize];
//attempt to re-try all requests that failed due to token expiration
for (NSURLRequest *failedRequest in weakSelf.failedRequests) {
[weakSelf sendTask:failedRequest successCallback:success errorCallback:errorCallback];
}
//clear failedRequests array and unlock alreadyRefreshingToken boolean
[weakSelf clearFailedRequests];
weakSelf.alreadyRefreshingToken = [NSNumber numberWithBool:NO];
NSLog(@"TOKEN REFRESHING SUCCESSFUL THO");
} errorCallback:^(NSString *error) {
NSLog(@"TOKEN NOT REFRESHABLE! HAVE TO LOG IN MANUALLY");
//clear failedRequests array
[weakSelf clearFailedRequests];
errorCallback(@"Your login session has expired");
}];
}
else {
NSLog(@"ALREADY REFRESHING TOKEN. JUST ADD TO FAILED LIST");
NSMutableArray *mutableFailedRequests = [weakSelf.failedRequests mutableCopy];
[mutableFailedRequests addObject:request];
weakSelf.failedRequests = [mutableFailedRequests copy];
}
}
}
else {
NSLog(@"ERROR STRING THO: %@", error);
errorCallback(error);
}
}];
}];
[task resume];
}
#pragma mark Custom Methods
-(void)clearFailedRequests {
NSMutableArray *mutableFailedRequests = [self.failedRequests mutableCopy];
[mutableFailedRequests removeAllObjects];
self.failedRequests = [mutableFailedRequests copy];
}
我这样做对吗?有一点让我有些偏执,那就是我并没有在某些时候真正调用
success
或error
回调。这会导致问题吗?请尝试使用[weakSelf sendTask],而不是使用[self sendTask:]。检查以下代码:
-(void)sendTask:(NSURLRequest*)request successCallback:(void (^)(NSDictionary*))success errorCallback:(void (^)(NSString*))errorCallback
{
__weak __typeof(self)weakSelf = self;
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{
[self parseResponse:response data:data fromRequest:request successCallback:success errorCallback:^(NSString *error)
{
//if auth token expired and getting "not authenticated" error (status 401)
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 401) {
[self refreshAuthenticationTokenWithSuccessCallback:^(NSDictionary *response) {
self.authToken = response[@"token"];
//attempt to re-try the request that failed due to token expiration
[weakSelf sendTask:request successCallback:success errorCallback:errorCallback];
} errorCallback:^(NSString *error) {
//two weeks have passed and the token is no longer refreshable
NSLog(@"TOKEN NOT REFRESHABLE! HAVE TO LOG IN MANUALLY");
}];
}
}];
}];
[task resume];
}
呜呜,谢谢你的接球。我忘了把脆弱的自我放在那里。但这将如何防止多个失败的请求同时尝试刷新令牌?不会,但它只修复了重试问题。