2

I am working on fixing a bug in an existing project. The trouble is that AFHTTPClient is expecting a valid JSON response, but the server is returning some gibberish like ""\" Operation complete\"" (all the quotes and brackets are in the return). This causes the operation to fail, and hit the fail block, because it can't parse the response. Despite that, the server is returning status code 200, and is happy that the operation is complete.

I have a class that extends AFHTTPClient like so (exert from my .h file)

@interface AuthClient : AFHTTPClient

  //blah blah blah

@end

In my implementation file the class gets initialized like so:

- (id)initWithBaseURL:(NSURL *)url{
    if (self = [super initWithBaseURL:url]) {        
        self.parameterEncoding = AFFormURLParameterEncoding;
        self.stringEncoding = NSASCIIStringEncoding;

        [self setDefaultHeader:@"Accept" value:@"application/json"];
        [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
    }

    return self;
}

The call I am making is done in the class mentioned above and happens like so:

- (void)destroyToken:(NSString *)token onCompletion:(void (^)(BOOL success))completion onFailure:(void (^)(NSError *error))failure{

    [self postPath:@"TheServerURL" parameters:@{@"token": token} success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSError *error;
        //Do some stuff
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        //Don't want to be here.
    }];
}

Inside the fail block the error is being returned in the error object's _userInfo section as:

[0] (null) @"NSDebugDescription" : @"JSON text did not start with array or object and option to allow fragments not set."

The error code is 3480.

From Googling around I gather I need to set something like NSJSONReadingAllowFragments, but I'm not sure how/where given the current setup. Does anyone have any ideas?

Rob
  • 23
  • 3
  • When the server responds with an invalid JSON, why is the service not fixed? – CouchDeveloper Nov 13 '13 at 23:27
  • The server fix is scheduled, but it won't be pushed for a while. It's beyond my control. However it is throwing off my testing schedule. – Rob Nov 15 '13 at 17:46

1 Answers1

1

It sounds like the response is not JSON at all. So, why not just accept the HTTP response itself, rather than try to handle it like JSON when it's not?

If you are submitting a JSON formed request, but just want the text response back, using AFNetworking 2.0 you can do something like:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:urlString parameters:@{@"token":token} success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    NSLog(@"responseString: %@", string);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

Or, in 1.x:

AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
client.parameterEncoding = AFJSONParameterEncoding;
NSMutableURLRequest *request = [client requestWithMethod:@"POST" path:path parameters:@{@"token" : token}];

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    NSLog(@"response: %@", string);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

[client enqueueHTTPRequestOperation:operation];
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I would prefer to do as you have suggested, but it is a large class, and it is 98% working. It's just the one end point that is returning invalid JSON. Refactoring the whole class would require an extensive trip back through QA so that isn't an option at the moment. Thank you for your excellent response though. In 99% of the situations this would be the perfect response! I am aware my situation is an edge case. – Rob Nov 14 '13 at 16:27
  • @Rob (I feel like I'm talking to myself:) Understood (and thanks for the accept even though I didn't really solve your question). Can you change your class to always use `AFHTTPRequestOperation` and then call `JSONObjectWithData`, returning the JSON object if that call succeeded and the `NSData` if not? Seems like potential change that wouldn't break the rest of your code. Clearly, as CouchDeveloper suggested, the best solution is to fix the web service to return JSON (perhaps doing so conditionally, checking the `Accept` parameter of the request to ensure backwards compatibility, if needed). – Rob Nov 14 '13 at 17:14