使用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
(2)然后把client.crt文件复制到iOS项目目录下,然后在Build Phases中的Copy Bundle Resources中选中crt文件进行添加:
(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的返回结果。