0

使用 Visual Studio for Mac,我创建了一个 RESFUL API(从 API 项目模板开发),它开箱即用地在以下 url 输出一个非常简单的 JSON 文件(即 ["value1","value2"]):https ://localhost:5001/api/values

因此,在后台在 Visual Studio 上运行 API 时,我也在同一台计算机上运行 XCode;因为我正在开发一个需要连接到 API url 并输出预期 JSON 响应的应用程序。

问题是由于信任错误而不断失败:“TIC SSL 信任错误...NSURLSession/NSURLConnection HTTP 加载失败”。

根据我的研究,我相信我需要将 localhost 的自签名证书安装到我的 XCode 模拟器上,以便它允许应用程序信任 url。如何访问此 localhost 证书?

或者这甚至是正确的方法吗?

生成信任错误的代码:

// Specify the base url...
static NSString *const API_URL = @"https://localhost:5001";
// Specify completed url ...
NSString *urlAppend = [NSString stringWithFormat:@"/api/values"];
NSString *urlStr = [[[NSString alloc] initWithString:API_URL]
stringByAppendingString:urlAppend];        

// Specify the URL object that can return JSON, XML, etc....
NSURL *url = [[NSURL alloc] initWithString:urlStr];

// Create an NSURLSessionDataTask that does the GET request at the specified URL (using NSURLSession shared session)...
NSURLSessionDataTask *task = [[NSURLSession sharedSession]
              dataTaskWithURL:url
              completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                  // Handle response (output respnose to log window))...
                  NSLog(@"%@", [output initWithData:data  encoding:(NSASCIIStringEncoding)] ? : @"no data");
              }];

// Start task ....
[task resume];
4

2 回答 2

0

你可以试试这个:在每个发出 HTTP 请求的 ViewController 的顶部,就在 imports 部分下面,添加以下代码:

@interface NSURLRequest (DummyInterface)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;
@end

然后,在你提出请求的地方,调用这个:

[request setHTTPBody:data];

[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];

NSError *error;
NSHTTPURLResponse  *response = nil;

NSData *data2 = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
于 2019-06-12T22:21:35.217 回答
0

解决此问题的最佳方法是对 localhost 开发服务器的 url执行手动服务器信任身份验证(在后台运行)。这是通过使用 NSURLSessionDelegate 的URLSession: didReceiveChallenge :completionHandler:委托方法来完成的;这将使您有机会匹配 localhost url 并在会话数据任务开始时手动信任它(在它由于不受信任的自签名证书而拒绝之前)。

就是这样:

第 1 步:将 NSURLSession 操作封装在一个类中,比如“Networking”,它实现了 NSURLSessionDelegate 协议;并添加手动信任您的本地主机 URL 的委托方法(指定为“DEV_URL”)。

// Networking.h
#import <Foundation/Foundation.h>

@interface Networking : NSObject <NSURLSessionDelegate>
- (void) fetchContentsOfUrl:(NSURL *)url
                 completion:(void (^)(NSData *data, NSError *error)) completionHandler;
@end
// Networking.m
#import "Networking.h"

static NSString *const DEV_URL = @"https://localhost:5001";
@implementation Networking
- (void) fetchContentsOfUrl:(NSURL *)url
                 completion:(void (^)(NSData * _Nullable, NSError * _Nullable))completionHandler {
    NSURLSession *dataSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];

    NSURLSessionDataTask *dataTask = [dataSession
                                      dataTaskWithURL:url
                                      completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

                                          if (completionHandler == nil) {
                                              return;
                                          }

                                          if (error){
                                              completionHandler(nil, error);
                                              return;
                                          }

                                          completionHandler(data, nil);
                                      }];

    [dataTask resume];
}

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURL* baseURL = [NSURL URLWithString:DEV_URL];
        if ([challenge.protectionSpace.host isEqualToString:baseURL.host]) {
            NSLog(@"trusting connection to host %@", challenge.protectionSpace.host);
            completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
        } else {
            NSLog(@"Not trusting connection to host %@", challenge.protectionSpace.host);
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
        }
    }
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
@end

第 2 步:将您的原始代码替换为 Networking 类的实例化并调用 fetchContentsOfUrl:completion: 方法,该方法调用 NSURLSessionDataTask,如下所示:

    Networking *networker = [[Networking alloc] init];
    [networker fetchContentsOfUrl:url completion:^(NSData *data, NSError *error) {        
        if (error == nil) {
            NSString *output = [NSString alloc];
            NSLog(@"%@", [output initWithData:data  encoding:(NSASCIIStringEncoding)] ? : @"no data");
        }
    }];

你都准备好了!

于 2019-06-27T21:00:16.920 回答