iOS - 在NSURLSession

时间:2016-01-16 05:26:26

标签: ios api authentication nsurlsession nsurlrequest

在我的应用中,我的服务器的2-4个API调用可以在我的API类NSURLSession内同时(异步)进行。为了向我的服务器发出API请求,我必须在每个HTTPHeaderField的{​​{1}}中提供身份验证令牌。该令牌有效期为一天,如果它在一天后失效,我需要刷新令牌。

我在API类的以下代码中执行此操作:

NSURLRequest

这个/*! * @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]; } 方法会在我在应用程序中发出的每个API请求中执行,所以我才意识到这是一个糟糕的方法。如果由于令牌无效(一天过去)而导致3个API请求失败,则所有这3个API请求都将尝试进行API调用以刷新身份验证令牌。

如果有一个API请求失败,有没有办法让我只刷新身份验证令牌,然后重新尝试失败的API调用?

修改

我编辑了问题的标题,表明我正在使用NSURLSession

进步

到目前为止,为了防止多个失败的API请求同时尝试刷新身份验证令牌,我对所有失败的请求都有一个sendTask,并且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回调。这会导致问题吗?

1 个答案:

答案 0 :(得分:-1)

不要使用[self sendTask:],而是尝试使用[weakSelf sendTask]。检查以下代码:

SELECT   DATE_FORMAT(TIMESTAMP, '%b %Y') AS `month`,
         COUNT(CASE UserType WHEN 'Administrator' THEN 1 END) AS Administrator,
         COUNT(CASE UserType WHEN 'No Role' THEN 1 END) AS NoRole,
         COUNT(CASE UserType WHEN 'Super User' THEN 1 END) AS SuperUser,
         COUNT(CASE UserType WHEN 'User' THEN 1 END) AS `User`
FROM     `user`
GROUP BY DATE_FORMAT(TIMESTAMP, '%b %Y')