您的位置:首页 > 理论基础 > 计算机网络

https信任证书的三种方式

2016-05-24 14:33 465 查看
苦逼的我调试AFNetworking发送https请求的bug ---------调试了一个上午,终于解决了

下面分享一下自己的经验:

一开始请求数据先要信任证书,然后才能请求数据,不过对于百度,apple官网这样的大网站就不需要信任证书了,

只需要信任一次服务器证书

在信任证书的时候有两种方式:

大家熟知的有NSURLSession和NSURLConnection两种信任证书的方式,我会重点将第三种:

如果不信任证书的话会报下面的错误:

// NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843)

// 原因:没有信任证书

一.NSURLSession的方式信任证书是通过代理的方式:

1.先懒加载全局的会话:

@property (nonatomic, strong) NSURLSession *session;
- (NSURLSession *)session {
if (_session == nil) {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
}
return _session;
}


2.发起数据任务

// url
NSURL *url = [NSURL URLWithString:@"https://域名"];

// 发起数据任务
[[self.session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@---%@",response,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}] resume];


3.代理方法中实现证书的信任-----------

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler {
/*
<NSURLProtectionSpace: 0x7fef2b686e20>:
Host:mail.itcast.cn,
Server:https,
Auth-Scheme:NSURLAuthenticationMethodServerTrust,
*/
// 判断是否是信任服务器证书
if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
// 告诉服务器,客户端信任证书
// 创建凭据对象
NSURLCredential *credntial = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
// 通过completionHandler告诉服务器信任证书
completionHandler(NSURLSessionAuthChallengeUseCredential,credntial);
}
NSLog(@"protectionSpace = %@",challenge.protectionSpace);
}


二.NSURLConnection的方式信任证书也是通过代理的方式:

1.发送请求:

// url
NSURL *url = [NSURL URLWithString:@"https://mail.itcast.cn"];

// request
NSURLRequest *request = [NSURLRequest requestWithURL:url];

// 发送请求
[NSURLConnection connectionWithRequest:request delegate:self];


2.信任证书
#pragma mark - NSURLConnectionDataDelegate 代理方法
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// 判断是否是信任服务器证书
if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
// 告诉服务器,客户端信任证书
// 创建凭据对象
NSURLCredential *credntial = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
// 告诉服务器信任证书
[challenge.sender useCredential:credntial forAuthenticationChallenge:challenge];
}
}


3.获取请求到的数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(@"data = %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}


三.AFNetworking的方式信任服务器证书:

先上代码:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy.validatesDomainName = NO;
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
//    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil];
[manager GET:@"https://域名" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {
NSLog(@"%@",downloadProgress);
} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
NSLog(@"%@---%@",[responseObject class],responseObject);
NSLog(@"%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@",error);
}];


注意解释遇到的坑:
1.https的协议直接请求的时候会报下面的错:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843)

2.设置属性

manager.securityPolicy.validatesDomainName =NO;

解决了证书信任的问题,也就是说设置上面的属性以后就可以信任证书了

但是问题没有解决:越到了经常遇到的问题,就是请求的数据打印有问题,

Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/html"

原因:

这是因为 AFNetworking默认把响应结果当成json来处理,(默认manager.responseSerializer = [AFJSONResponseSerializer serializer]) ,很显然,我们请求的百度首页 返回的并不是一个json文本,而是一个html网页,但是AFNetworking并不知道,它坚信请求的结果就是一个json文本!然后固执地以json的形式去解析,显然没办法把一个网页解析成一个字典或者数组,所以产生了上述错误.

然而,我们期望它能够正确地处理这个情形,而不是提示一个错误.

这时候 你必须告诉AFNetworking:别把这个网页当json来处理!

解决办法:

只需要在发送请求前加入:
manager.responseSerializer = [AFHTTPResponseSerializer serializer]


以上步骤就可以实现https证书的信任和正确的获取例如baidu.com首页的html的源码...

附加说明:
网页上加载的数据本质是字符串,我们将获取到的网页数据通过二进制转字符串的形式可以讲网页数据进行打印:

NSLog(@"%@",[[NSStringalloc]initWithData:responseObjectencoding:NSUTF8StringEncoding]);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: