iOS 9 与 REST Web 服务的连接失败

iOS 9 Failed Connection to REST Web Service

我对开发 iOS 应用程序有点陌生,我需要在此应用程序中做的事情之一是连接到 REST Web 服务。我已经在 Postman Extension 中测试了 WS,一切正常,但我似乎无法通过 iOS 应用程序做同样的事情。这是我用来尝试建立连接的代码:

NSString *wsAuth = [NSString stringWithFormat:@"Basic \%@", [[@"USER:PASS" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:nil]];
NSMutableDictionary *post = [[NSMutableDictionary alloc]init];
[post setValue:login forKey:@"user"];
[post setValue:pass forKey:@"pass"];
NSArray *arr = [NSArray arrayWithObjects:post, nil];
NSData *jsonPost = [NSJSONSerialization dataWithJSONObject:arr options:0 error:nil];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://mywebservice.mywebsite.com/auth/"]];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:jsonPost];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"%d", [jsonPost length]] forHTTPHeaderField:@"Content-Length"];
[request setValue:wsAuth forHTTPHeaderField:@"Authorization"];

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

NSHTTPURLResponse *response = nil;
NSError *error = nil;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

if([response statusCode] >=200 && [response statusCode] <300) {
    // Process data...
}
else {
    // Present error...
}

我从 Xcode 收到以下错误:

2016-03-16 11:02:34.658 [31742:2969162] Response = (null)

2016-03-16 11:02:34.659 [31742:2969162] Error =
Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."
UserInfo={NSErrorFailingURLStringKey=https://mywebservice.mywebsite.com/auth/,
_kCFStreamErrorCodeKey=-2102,
NSErrorFailingURLKey=https://mywebservice.mywebsite.com/auth/,
NSLocalizedDescription=The request timed out.,
_kCFStreamErrorDomainKey=4,
NSUnderlyingError=0x7aa5b510 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "The request timed out."
UserInfo={_kCFStreamErrorCodeKey=-2102,
NSErrorFailingURLStringKey=https://mywebservice.mywebsite.com/auth/, 
NSErrorFailingURLKey=https://mywebservice.mywebsite.com/auth/,
NSLocalizedDescription=The request timed out.,
_kCFStreamErrorDomainKey=4}}}

2016-03-16 11:02:34.693 [31742:2969383] CFNetwork SSLHandshake failed (-9806)
2016-03-16 11:02:34.799 [31742:2969383] CFNetwork SSLHandshake failed (-9802)
2016-03-16 11:02:34.889 [31742:2969383] CFNetwork SSLHandshake failed (-9802)
2016-03-16 11:02:34.890 [31742:2969383] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

还有几件事要知道。我将其编程为需要与 iOS 8 或更新版本一起使用的 iOS 9 应用程序,并且我在 Xcode 7 中执行此操作。任何帮助将不胜感激。

您只需在 info.plist 文件的 NSAppTransportSecurity 词典中将 NSAllowsArbitraryLoads 键添加到 YES

好吧,我自己解决了这个问题。我想发出同步请求不起作用,所以我切换到异步。这给了我一个更准确的错误,它告诉我我没有传递 JSON 对象,而是传递了一个数组,其中第一个也是唯一的条目是 JSON 对象,这导致身份验证失败。

澄清一下,此解决方案包含几个与 RESTful Web 服务通信的对象。这是通过 POST 完成的,使用 JSON 对象作为 POST 变量。此 Web 服务需要基本身份验证,这是通过第 1 行和第 15 行的代码实现的。最后,这一切都基于安全连接和最新 SSL 证书背后的 Web 服务。我不是 100% 确定 HTTP 请求或自签名证书的解决方法...

旁注:我从我的 info.plist 文件中删除了 NSAllowsArbitraryLoads 键和 NSAppTransportSecurity 字典,这个解决方案仍然有效。

下面是使我成功连接到我的安全 Web 服务的代码:

NSString *wsAuth = [NSString stringWithFormat:@"Basic \%@", [[@"USER:PASS" dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]];
NSMutableDictionary *post = [[NSMutableDictionary alloc]init];
[post setValue:login forKey:@"user"];
[post setValue:pass forKey:@"pass"];
NSArray *arr = [NSArray arrayWithObjects:post, nil];
// Note the first value of the array is being referenced, not the entire array.
NSData *jsonPost = [NSJSONSerialization dataWithJSONObject:arr[0] options:0 error:nil];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://mywebservice.mywebsite.com/auth/"]];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:jsonPost];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:[NSString stringWithFormat:@"%d", [jsonPost length]] forHTTPHeaderField:@"Content-Length"];
[request setValue:wsAuth forHTTPHeaderField:@"Authorization"];

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
    if ([data length] >0 && error == nil) {
        // Process data here...
    }
    else if ([data length] == 0 && error == nil) {
        NSLog(@"Empty Response. Check your credentials.");
    }
    else if (error != nil) {
        NSLog(@"Error = %@", error);
    }
}];