api - iOS - Re-Attempt Failed NSURLRequests In NSURLSession -
in app, 2-4 api calls server can happening @ same time (asynchronously) within api class's nsurlsession
. in order make api requests server, must supply authentication token in httpheaderfield
of each nsurlrequest
. token valid 1 day, , if becomes invalid after 1 day, need refresh token.
i in following code in api class:
/*! * @brief sends request nshttpurlresponse. method private. * @param request request send. * @param success block called if request successful. * @param error block called if 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 , getting "not authenticated" error (status 401) nshttpurlresponse *httpresp = (nshttpurlresponse*) response; if (httpresp.statuscode == 401) { [self refreshauthenticationtokenwithsuccesscallback:^(nsdictionary *response) { self.authtoken = response[@"token"]; //attempt re-try request failed due token expiration [self sendtask:request successcallback:success errorcallback:errorcallback]; } errorcallback:^(nsstring *error) { //two weeks have passed , token no longer refreshable nslog(@"token not refreshable! have log in manually"); }]; } }]; }]; [task resume]; }
this sendtask
method gets executed every api request make in app, realized bad way of doing it. if 3 api requests fail due token being invalid (one day passed), 3 of these api requests going attempt make api call refresh authentication token.
is there way me to, in case 1 of api requests fail, refresh authentication token once , re-attempt failed api calls?
edit
i edited title of question indicate i'm working nsurlsession
progress
so far, prevent several failed api requests trying refresh authentication token @ same time, have nsarray
failed requests , nsnumber
serves lock make sure authentication token trying refreshed once. in following code:
-(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 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 re-try requests failed due token expiration (nsurlrequest *failedrequest in weakself.failedrequests) { [weakself sendtask:failedrequest successcallback:success errorcallback:errorcallback]; } //clear failedrequests array , unlock alreadyrefreshingtoken boolean [weakself clearfailedrequests]; weakself.alreadyrefreshingtoken = [nsnumber numberwithbool:no]; nslog(@"token refreshing successful tho"); } errorcallback:^(nsstring *error) { nslog(@"token not refreshable! have log in manually"); //clear failedrequests array [weakself clearfailedrequests]; errorcallback(@"your login session has expired"); }]; } else { nslog(@"already refreshing token. add 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]; }
am going correctly? 1 part i'm paranoid i'm not calling success
or error
callback @ points. can lead problems?
instead of using [self sendtask:], try [weakself sendtask]. check below code:
-(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 , getting "not authenticated" error (status 401) nshttpurlresponse *httpresp = (nshttpurlresponse*) response; if (httpresp.statuscode == 401) { [self refreshauthenticationtokenwithsuccesscallback:^(nsdictionary *response) { self.authtoken = response[@"token"]; //attempt re-try request failed due token expiration [weakself sendtask:request successcallback:success errorcallback:errorcallback]; } errorcallback:^(nsstring *error) { //two weeks have passed , token no longer refreshable nslog(@"token not refreshable! have log in manually"); }]; } }]; }]; [task resume]; }
Comments
Post a Comment