简体   繁体   中英

IOS Issues with sendAsynchronousRequest

I'm having some serious issue with [NSURLConnection sendAsynchronousRequest: queue: completionHandler:] . I am using a rest proxy to log in and authenticate users. The following I use to log in is shown below:

    //Display the progress HUB
    [SVProgressHUD showWithStatus:@"Signing Up..." maskType:SVProgressHUDMaskTypeClear];

    NSError *error;
    [self setUserCredentials];

    //assign the parentView controller to the sender and email to the local class variables
    parentView = sender;
    userEmail = email;

    // create json object for a users session
    NSDictionary* session = [NSDictionary dictionaryWithObjectsAndKeys:
                             email, @"email",
                             password, @"password",
                             [NSDictionary dictionaryWithObjectsAndKeys:
                              [[UIDevice currentDevice] model], @"device",
                              [[UIDevice currentDevice] identifierForVendor].UUIDString, @"device_id",
                              @"APNS", @"push_to",
                              [[NSUserDefaults standardUserDefaults] stringForKey:@"push_id"], @"push_id",
                              nil],
                             @"mession",
                             nil];

    NSData *jsonSession = [NSJSONSerialization dataWithJSONObject:session options:NSJSONWritingPrettyPrinted error:&error];
    NSString *url = [NSString stringWithFormat:@"%@api/v1/messions.json", CoffeeURL];

    NSLog(@"URL: %@", url);

    NSURL *URL = [NSURL URLWithString:url];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL
                                                           cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                       timeoutInterval:30.0];

    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request setValue:[NSString stringWithFormat:@"%d", [jsonSession length]] forHTTPHeaderField:@"Content-Length"];
    [request setHTTPBody:jsonSession];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

        NSLog(@"Length: %d", data.length);

        if (error == nil)
        {
            //if no error ocours set the user defualts and create the mession and log into the app
            NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSDictionary *JSONResponse = [NSJSONSerialization JSONObjectWithData:[dataString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error: &error];

            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;

            NSLog(@"JSON: %@", JSONResponse);
            NSLog(@"Response: %d", httpResponse.statusCode);

            if (JSONResponse != nil && httpResponse.statusCode == 200)
            {
                [self setUserDefualts:password sessionToUse:JSONResponse deckController:viewDeck sender:sender];
            }

            [SVProgressHUD dismiss];
        }
        else
        {
            NSLog(@"Error: %@", error);

            //Dismiss progress HUB here and inform user that an internal error has occured
            [SVProgressHUD dismiss];
            NSString *errorString = @"Sorry, an error has occoured while connecting to the Coffee server.";
            UIAlertView *errorAlertView = [[UIAlertView alloc] initWithTitle:@"Error" message:errorString delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
            [errorAlertView show];
        }
    }];

When I log in with valid user credentials this code works properly. When I use invalid credentials the server sends a 401 and a null JSON object to the iOS client. This should return an error = nil and a status code of 401 with a valid non-null response object. For some reason an error is returned and the response is nil:

Error: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed.
(NSURLErrorDomain error -1012.)" UserInfo=0x1cd53b50 
{NSErrorFailingURLKey=http://192.155.94.183/api/v1/messions.json, 
NSErrorFailingURLStringKey=http://192.155.94.183/api/v1/messions.json, 
NSUnderlyingError=0x1cdc2b10 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork
 error -1012.)"}

This is making it very hard for me to differ between a error that has happened while the request is being sent and a 401 error that is generated by the server when the user's credentials don't match up with the backend. When I tried creating and handling the request with:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];

and the NSURLDelegate:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    NSLog(@"Called Outside!");

    NSDictionary *jsonSession;
    NSUserDefaults *userInfo = [NSUserDefaults standardUserDefaults];
    NSLog(@"Succeeded! Received %d bytes of data", [responseData length]);
    recievedResponse = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

    NSError *err = nil;
    jsonSession = [NSJSONSerialization JSONObjectWithData:[recievedResponse dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&err];

    if ([connection.originalRequest.URL isEqual:[NSURL URLWithString:[NSString stringWithFormat:@"%@api/v1/messions.json", CoffeeURL]]])
    {
        NSLog(@"Status: %d", httpResponse.statusCode);
        NSLog(@"JSON: %@", jsonSession);
        NSLog(@"Called Inside!");
    }
}

The response returned is valid, no error is thrown and the status code is equal to 401 when the user enters invalid credentials. Why would this work with (void)connectionDidFinishLoading:(NSURLConnection *)connection but not with [NSURLConnection sendAsynchronousRequest: queue: completionHandler:] ?

Don't rely on an error not being generated when the URL handling system receives an error HTTP status code (ie not 2xx ).

Instead, use the returned response which gives you access to the HTTP status code (check the class at runtime and cast to NSHTTPURLResponse so you can access statusCode ).

It turned out to be a bug in our back-end server. Sometimes it will send very weird response codes that are handled improperly by the iOS NSURLConnection libraries. In this particular case it showed up as a domain error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM