2016-01-16 3 views
5

В моем приложении 2-4 API-вызовы на мой сервер могут происходить одновременно (асинхронно) в пределах моего класса API NSURLSession. Чтобы сделать запросы API на мой сервер, я должен предоставить токен аутентификации в HTTPHeaderField каждого NSURLRequest. Токен действителен в течение одного дня, и если он становится недействительным через один день, мне нужно обновить токен.iOS - повторная попытка не удалось NSURLRequests в NSURLSession

Я делаю это в следующем коде в моем классе 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 не выполняются из-за того, что токен недействителен (один день прошел), все три этих запроса API будут пытаться заставить вызов API обновить токен аутентификации.

Есть ли способ для меня, если один из запросов API не работает, обновите токен аутентификации только один раз, а затем повторите попытку неудачных вызовов API?

EDIT

Я отредактировал заголовок вопроса, чтобы указать, что я работаю с NSURLSession

ИДУТ

До сих пор, чтобы предотвратить несколько неудачных API запросы от попыток обновить токен аутентификации в одно и то же время, у меня есть NSArray для всех неудавшихся запросов a nd a 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]; 
} 

Я правильно понял? Одна часть, о которой я параноик, заключается в том, что я на самом деле не вызываю обратный вызов или error в определенных точках. Может ли это привести к проблемам?

ответ

-1

Вместо использования [self sendTask:], попробуйте использовать [weakSelf 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]; 
} 
+0

Woops, спасибо за улов. Я забыл поставить там слабое я. Но как это будет мешать нескольким неудавшимся запросам пытаться обновить токен одновременно? – Rafi

+0

Это не будет, но он исправляет только проблему повторения. –