带参数的 NSMutableURLRequest - 无法解析响应

Posted

技术标签:

【中文标题】带参数的 NSMutableURLRequest - 无法解析响应【英文标题】:NSMutableURLRequest with parameter - cannot parse response 【发布时间】:2014-10-29 20:46:37 【问题描述】:

我正在尝试创建与打印出 JSON 代码的 URL 的连接,然后对其进行解析和处理。我的 URL 有一个名为 bypass 的参数。网址如下所示:

http://www.getchanged.net/json.asp?bypass=MIGCBgkrBgEEAYI3WAOxxx

我没有设法解决这个问题,因为它总是说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]];

错误:

2014-10-29 21:43:39.529 TestMap[57987:1931535] Connection failed with error: cannot parse response

这里有什么问题?

请注意:我稍微替换了绕过哈希,因为它包含敏感数据。该网站运行正常,正在打印 JSON 输出。

【问题讨论】:

调试此类错误的最佳方法是设置断点并实际查看服务器给您的响应。 JSON 解析通常会失败,因为服务器返回带有 html 正文的 500 错误,如果在这种情况下您知道您的请求是错误的。否则,如果服务器返回正确的结果,则可能是服务器格式化响应的方式有问题 【参考方案1】:

几个观察:

    关键问题是您发出GET 请求,但在请求正文中提供bypass 参数。对于POST请求,参数应该添加到body中,但是对于GET请求,它应该添加到URL中。

    如果此 bypass 键可能包含保留字符(例如空格、&+ 等),则您需要对为 @ 提供的值进行百分比转义987654329@。如果您保证它只是字母数字,您可以不用百分比转义它,但作为一般规则,您应该始终对 HTTP 参数进行百分比转义。

    虽然第 1 点可能会解决此问题,但有时 Web 服务会期望设置某些标头字段。例如,通常设置请求的标头Content-Type(例如,这看起来像请求的Content-Type应该是application/x-www-form-urlencoded)。

    您说您收到一条错误消息,“连接失败并出现错误:无法解析响应”。您尚未向我们展示产生此错误的代码,但我认为这是在您的代码尝试将响应解析为 JSON 时生成的。

    以后在诊断这些问题时,我发现实际检查响应的详细信息很有用。值得注意的是,响应的标头将包含在NSURLResponse 中(实际上是NSHTTPURLResponse,它有一个statusCode 数值,可以非常有启发性)。响应的主体通常是错误的字符串表示形式(通常当 Web 服务失败时,它会生成错误的文本或 HTML 描述)。

    以后每当您遇到此类错误时,请始终查看statusCode 和服务器返回的任何文本,因为这将帮助您诊断正在发生的事情。它将比一般的“我无法解析响应”消息提供更多信息。

    如果您的 Web 界面可以正常工作,而应用程序界面不能正常工作,有时使用Charles 之类的工具来观察 Web 浏览器生成的请求并将其与应用程序。这在诊断这类问题时非常有用。

    此外,如果您使用 Charles 之类的东西,这允许您手动检查服务器的状态代码和文本响应,我建议您可以在第 4 点中以编程方式处理。

【讨论】:

第一点帮助了我。谢谢【参考方案2】:

把请求HTTPMethod改成POST就可以了。

@property (复制) NSData *HTTPBody;

@discussion This data is sent as the message body of the request, as
in done in an HTTP POST request.

你也可以这样使用GET,将整个url设置为请求url,不设置HTTPBody。

NSString *urlAsString = @"http://www.getchanged.net/json.asp";
urlAsString = [urlAsString stringByAppendingString:@"?bypass=MIGCBgkrBgEEAYI3WAOxxx"];
NSURL *aUrl = [NSURL URLWithString:urlAsString];

这个site 确认这是一个有效的JSON 字符串,但是其中有一些"\r\n",这段代码似乎能够通过从字符串中删除"\r\n" 来解决问题。

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];

【讨论】:

当我尝试两者时,我得到:Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x171a6cec0 NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set. 看起来像 JSON 文本错误,是哪一行导致的?无论如何,这里是project 供参考。 感谢您的项目。我也得到(空)它。您可以检查正确的绕过哈希吗? (MIGCBgkrBgEEAYI3WAOgdT)【参考方案3】:

我想这就是你想要的:

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];

这会打印出来(在控制台中):

2014-11-06 17:09:21.659 ] string: 
"stores":[

]

2014-11-06 17:09:21.659 ] dict: 
    stores =     (
    );

我让它将数据打印为 json 字符串和字典,因为我不确定你想要什么。

【讨论】:

刚刚添加了一个版本的代码到有 NSMutableURLRequest 的答案【参考方案4】:

除了 Rob 很好解决的问题之外,来自所列网站的 JSON 返回没有验证:

我已经使用 URL 和绕过哈希(您在 cmets 中发布)尝试了几个验证器,但 JSON 无效。返回的典型错误:

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'

正如json.org 中解释的那样,任何字符串值都可以包含

除 " 或 \ 或控制字符之外的任何 UNICODE 字符

所以 字符串值 具有如下结构:

注意换行符和回车所需的转义格式。

考虑到这一点,并查看在Charles 中捕获的原始输出,您可以看到第 26 行第 84 列在价值。

服务器应该在发送这些值之前对其进行转义。

顺便说一句,JSON 在数组、对象和值之外有很多空格 (x20) 和 CRLF,虽然不会影响 JSON,但它们是不必要的,并且会增加数据传输。

【讨论】:

【参考方案5】:

以下工作正常:

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);

    

但可能会发生这样的情况 - 正如您在注释中提到的那样 - 绕过哈希已更改以隐藏您的敏感数据,该数据可能包含一些特殊字符或无效的 JSON,导致您的 JSON 解析失败。 如果您不想共享该数据,您可以使用虚拟数据编辑原始响应(不要替换特殊字符),并在此处共享,这将有助于大家进行更多调试。

【讨论】:

以上是关于带参数的 NSMutableURLRequest - 无法解析响应的主要内容,如果未能解决你的问题,请参考以下文章

如何在上传带参数的图像时使用 AFNetworking 2.0 设置 cookie?

无法使用类型为“(NSMutableURLRequest,(_,_,_) throws -> _)”的参数列表调用“dataTaskWithRequest”

AFNetworking 使用 NSMutableURLRequest 上传?

使用 NSMutableURLRequest 请求

NSMutableURLRequest 发送部分帖子正文

NSMutableURLRequest 的问题