Reputation: 5742
I am trying to create a connection to a URL that prints out JSON code that is then parsed and processed. My URL has a parameter called bypass
. The URL looks like this:
http://www.getchanged.net/json.asp?bypass=MIGCBgkrBgEEAYI3WAOxxx
I did not manage to solve this issue as it always says Connection failed with error: cannot parse response
NSURL *aUrl = [NSURL URLWithString:@"http://www.getchanged.net/json.asp"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:@"GET"];
NSString *postString = @"bypass=MIGCBgkrBgEEAYI3WAOxxx";
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
Error:
2014-10-29 21:43:39.529 TestMap[57987:1931535] Connection failed with error: cannot parse response
What is wrong here?
Please note: I replaced the bypass hash a bit because it contains sensible data. The website works and is printing out JSON output.
Upvotes: 3
Views: 5762
Reputation: 4584
The following works fine:
NSURL *aUrl = [NSURL URLWithString:@"http://www.getchanged.net/json.asp?bypass=MIGCBgkrBgEEAYI3WAOxxx"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:@"GET"];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (!error) {
NSLog(@"Response String : %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"Parsed Data : %@", json);
}
But it may happen that - as you mentioned in your Note - bypass hash is changed to hide your sensible data, that data may having some special characters or invalid JSON that is failing your JSON parsing. If you don't wan't to share that data you can edit the original response with dummy data (do not replace special characters), and share here that will help all to debug more.
Upvotes: 0
Reputation: 9330
Apart from the issue well addressed by Rob, the JSON return from the listed website doesn't validate:
I've tried several validators with the URL and bypass hash (you posted in comments) and the JSON is invalid. Typical error returned:
JSON Content: Invalid JSON at line 26, column 84
Parse error on line 26:
...rtragen", "adresse":"fairtragen - GmbH
-----------------------^
Expecting 'STRING', 'NUMBER', 'NULL', 'TRUE', 'FALSE', '{', '[', got 'undefined'
As explained at json.org any string value can contain
any UNICODE character except " or \ or control character
So a string value has as structure like this:
Note the escape format required for newlines and carriage returns.
Taking that into account, and looking at the raw output captured in Charles you can see that line 26, column 84 contains x0d
followed by x0a
(i.e. an old windows style CRLF) in the middle of a value.
The server should be escaping these values before sending them out.
By the way, the JSON has lots of spaces (x20
) and CRLF through out, outside of the array, objects and values, that while not affecting the JSON, are unnecessary and do bulk up the data transfer.
Upvotes: 1
Reputation: 438257
A couple of observations:
The key issue is that you are issuing a GET
request, but supplying the bypass
parameter in the body of the request. For POST
requests, the parameters should be added to the body, but for GET
requests, it should be added to the URL.
If this bypass
key could ever contain reserved characters (such as spaces, &
, +
, etc.), you'd want to percent-escape the value you're supplying for bypass
. If you are guaranteed that it will be only alphanumeric, you can get away without percent escaping it, but as a general rule, you should always percent-escape HTTP parameters.
While point #1 will probably resolve this issue, sometimes web services will expect certain header fields to be set. For example, it is common to set Content-Type
header of the request (e.g., this looks like the Content-Type
of the request should be application/x-www-form-urlencoded
).
You say that you are receiving an error message, "Connection failed with error: cannot parse response". You haven't shown us the code that is producing this error, but I presume this was generated when your code tried to parse a response as JSON when it wasn't.
In the future, when diagnosing these issues, I find it useful to actually examine the details of the response. Notably, the header of the response will be contained in the NSURLResponse
(which will actually be a NSHTTPURLResponse
which has a statusCode
numeric value which can be very illuminating). The body of the response will often be a string representation of the error (often when a web service fails it generates text or HTML description of the error).
Whenever you get errors like this in the future, always look at the statusCode
and the text of whatever the server returned, as that would help you diagnose what's going on. It will be more informative than a generic "I cannot parse the response" message.
If you have a web interface that works, and an application interface that doesn't, it's sometimes useful to use a tool like Charles to observe the request generated by the web browser and compare that to the request generated by the app. This can be invaluable when diagnosing these sorts of issues.
Also, if you use something like Charles, this allows you to manually inspect the status code and text response of the server which I suggested you might handle programmatically in point #4.
Upvotes: 4
Reputation: 5518
I think this is what you want:
NSString * bypassId = @"MIGCBgkrBgEEAYI3WAOxxx";
NSURL *aUrl = [NSURL URLWithString:[NSString stringWithFormat:@"http://www.getchanged.net/json.asp?bypass=%@",bypassId]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:aUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *jsonAsString = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(@"string: %@",jsonAsString);
NSDictionary *jsonAsObject = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: nil];
NSLog(@"dict: %@",jsonAsObject);
}] resume];
This prints out (in the console):
2014-11-06 17:09:21.659 ] string:
{"stores":[
]}
2014-11-06 17:09:21.659 ] dict: {
stores = (
);
}
I have it printing the data as a json string and dictionary because I'm not exactly sure what you want.
Upvotes: 2
Reputation: 13766
Change the request HTTPMethod
to POST
, you will be fine.
@property (copy) NSData *HTTPBody;
@discussion This data is sent as the message body of the request, as
in done in an HTTP POST request.
You can also use GET
in this way, set the whole url as the request url and don't set the HTTPBody.
NSString *urlAsString = @"http://www.getchanged.net/json.asp";
urlAsString = [urlAsString stringByAppendingString:@"?bypass=MIGCBgkrBgEEAYI3WAOxxx"];
NSURL *aUrl = [NSURL URLWithString:urlAsString];
This site confirmed this is a valid JSON string, however there is some "\r\n"
in it, this code seems to be able to fix the problem by removing the "\r\n"
from the string.
NSString* receivedString = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
receivedString = [receivedString stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];
NSData *data = [receivedString dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
Upvotes: 2