AFNetworking访问https出现"NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813"

       使用AFNetworking来访问http请求非常方便快捷,最简单的请求代码如下:

#import "HSTestHTTPSViewController.h"
#import <AFNetworking/AFNetworking.h>

@interface HSTestHTTPSViewController ()

@end

@implementation HSTestHTTPSViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *URLString = @"http://localhost:8000";

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    [manager GET:URLString parameters:nil progress:nil
          success:^(NSURLSessionDataTask *task, id responseObject) {
              //返回NSData,转化为String输出
              NSString *JSONString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
              NSLog(@"%@", JSONString);
          }
          failure:^(NSURLSessionDataTask *task, NSError *error) {
              NSLog(@"%@", error);
          }];
}

@end

      当然,使用上述代码来请求http能够成功,但是当我们要访问https的时候,如果仅仅是把上述的请求URL修改成对应的https,那么很有可能会出现如下报错:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. 
You might be connecting to a server that is pretending to be “localhost” which could put your confidential information at risk." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x600000108820>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813, NSErrorPeerCertificateChainKey=
(
    "<cert(0x7f9bcd84ea00) s: chenyufeng i: chenyufeng>"
), NSUnderlyingError=0x600000057730 {Error Domain=kCFErrorDomainCFNetwork Code=-1202 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x600000108820>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9813, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9813, kCFStreamPropertySSLPeerCertificates=
(
    "<cert(0x7f9bcd84ea00) s: chenyufeng i: chenyufeng>"
)}}, NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “localhost” which could put your confidential information at risk., NSErrorFailingURLKey=https://localhost:8001/, NSErrorFailingURLStringKey=https://localhost:8001/, NSErrorClientCertificateStateKey=0}


     出现以上问题的主要原因是https证书是自签名证书,没有经过第三方机构认证(关于生成自签名证书和nodejs配置自签名证书可以了解《nodejs开发——express配置自签名https服务器》这篇博客)。一个经过认证的证书一般不会出现以上问题。那么在服务端https证书不变的情况下,如何在iOS客户端修复该问题呢?

(1)从服务端那里拿到证书crt后缀文件,我这里的文件名为“file.crt”. (建议看下nodejs开发——express配置自签名https服务器)。然后使用该crt文件生成用于iOS的.cer文件,我这里的文件名为“client.cer”.  生成命令如下:

openssl x509 -in file.crt -out client.cer -outform der


生成前crt与生成后的cer文件如下:




(2)然后把client.cer文件复制到iOS项目目录下,然后在Build Phases中的Copy Bundle Resources中选中该cer文件进行添加:






(3)然后把AFN的网络请求代码修改如下:主要增加Security设置

#import "HSTestHTTPSViewController.h"
#import <AFNetworking/AFNetworking.h>

@interface HSTestHTTPSViewController ()

@end

@implementation HSTestHTTPSViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *URLString = @"https://localhost:8001";

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    //增加AFSecurityPolicy设置
    AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    securityPolicy.allowInvalidCertificates = YES;
    securityPolicy.validatesDomainName = NO;
    manager.securityPolicy = securityPolicy;

    [manager GET:URLString parameters:nil progress:nil
          success:^(NSURLSessionDataTask *task, id responseObject) {
              //返回NSData,转化为String输出
              NSString *JSONString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
              NSLog(@"%@", JSONString);
          }
          failure:^(NSURLSessionDataTask *task, NSError *error) {
              NSLog(@"%@", error);
          }];
}

@end

      经过测试,能成功接收到https的返回结果。


你可能感兴趣的:(https,AFNetworking)