NSURLSession-HTTP同步和异步请求
2016-12-05 20:54
183 查看
从iOS9苹果废除NSURLConnection,建议用NSURLSession
NSURLSession没有直接同步请求的方法。想使用NSURLSession进行同步请求,即数据获取后才继续执行后面代码,使用信号、信号量可以实现。
这里先贴上异步请求代码
typedef enum {
HttpRequestTypePost,
HttpRequestTypeGet
}HttpRequestType;
typedef void(^HttpSuccessBlock)(NSDictionary *successDic);
typedef void(^HttpFailedBlock)(NSError *error);
其中有一步设置了session 的代理,可通过代理方法验证https请求证书
如果不需要证书验证,可以简单的进行默认设置
在上面异步请求的基础上,封装同步请求即可,使用信号量dispatch_semaphore_t、dispatch_semaphore_signal、dispatch_semaphore_wait等待数据返回
网络正常,打印的过程应该是
正在数据加载1 -> 正在数据加载2 -> 数据加载完毕
注意: 调用这个同步http请求不可以在主线程中,否则会造成卡死。需要单独开启一个线程进行数据请求
可以像下面这样
参考:
GCD中信号量的介绍 http://blog.csdn.net/eduora_meimei/article/details/23129977
https证书验证 http://www.jianshu.com/p/31bcddf44b8d
iOS-https http://www.jianshu.com/p/4b5d2d47833d
NSURLSession没有直接同步请求的方法。想使用NSURLSession进行同步请求,即数据获取后才继续执行后面代码,使用信号、信号量可以实现。
这里先贴上异步请求代码
typedef enum {
HttpRequestTypePost,
HttpRequestTypeGet
}HttpRequestType;
typedef void(^HttpSuccessBlock)(NSDictionary *successDic);
typedef void(^HttpFailedBlock)(NSError *error);
- (void)sendHttpRequestWithType:(HttpRequstType)type URL:(NSString *)url parameters:(NSDictionary *)params successBlock:(HttpSuccessBlock) successBlock faildBlock:(HttpFailedBlock) failedBlock { NSURL *URL = [NSURL URLWithString:url]; NSMutableURLRequest *theRequest = [[NSMutableURLRequest alloc] initWithURL:URL]; if (params != nil) { NSData *postData = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil]; [theRequest setHTTPBody:postData]; } NSString *methodType = (type == HttpRequstTypeGet ? @"GET" : @"POST"); [theRequest setHTTPMethod:methodType]; [theRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; [theRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"]; NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString*)@"CFBundleShortVersionString"]; NSString *iOSVersion = [[UIDevice currentDevice] systemVersion]; [theRequest setValue:[NSString stringWithFormat:@"%@/%@ ios/%@",@"sky",appVersion,iOSVersion] forHTTPHeaderField:@"User-Agent"]; NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:theRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { if (failedBlock) { failedBlock(error); } } else { if (data) { NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; if (successBlock) { successBlock(dic); } } } }]; [dataTask resume]; }
其中有一步设置了session 的代理,可通过代理方法验证https请求证书
#pragma mark - https证书验证 //http请求证书不可信任,就忽略 - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { /* 调用自定义的验证过程 */ if ([self wulianCustomValidation:challenge]) { // NSLog(@"证书可信任"); completionHandler(NSURLSessionAuthChallengeUseCredential , [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust]); }else { //验证证书不通过 //当执行到这的时候应该去排查一下具体为什么没过,可以看一下是否换证书了,是否是用GoDaddyRootCA或其直接签发的子证书签发的 // NSLog(@"证书不可信任"); completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge , nil); } }else { // NSLog(@"默认处理证书"); completionHandler(NSURLSessionAuthChallengePerformDefaultHandling , nil); } } - (BOOL)wulianCustomValidation:(NSURLAuthenticationChallenge *)challenge { //获得工程中的证书 // 获取cer格式CA证书路径 NSString *cerPath; if (isTest) { cerPath = [[NSBundle mainBundle] pathForResource:@"WL_test.sh.gg.root" ofType:@"cer"]; }else { cerPath = [[NSBundle mainBundle] pathForResource:@"WL_hw.pu.sh.gg.root" ofType:@"cer"]; } // 提取二进制内容 NSData *cerData = [NSData dataWithContentsOfFile:cerPath]; // 根据二进制内容提取证书信息 SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)cerData); // 形成钥匙链 NSArray * chain = [NSArray arrayWithObject:(__bridge id)(caRef)]; CFArrayRef caChainArrayRef = CFBridgingRetain(chain); // 取出服务器证书 SecTrustRef trust = [[challenge protectionSpace] serverTrust]; //初始化验证结果值 SecTrustResultType trustResult = kSecTrustResultInvalid; int err = SecTrustSetAnchorCertificates(trust, caChainArrayRef); if (err == noErr) { // 用CA证书验证服务器证书 err = SecTrustEvaluate(trust, &trustResult); } // 检查结果 kSecTrustResultConfirm 当值是这个时应询问用户许可,但这个值在iOS7.0后废弃了,系统支持到7.0 可以不管理这个值 BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified)); #warning 使用根证书验证存在服务器证书如果不是我们使用的GoDaddyRootCA签发的这个子证书签发的(另一个子证书签发)也能校验过 return trusted; }
如果不需要证书验证,可以简单的进行默认设置
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential , card); }else { completionHandler(NSURLSessionAuthChallengePerformDefaultHandling , nil); } }
在上面异步请求的基础上,封装同步请求即可,使用信号量dispatch_semaphore_t、dispatch_semaphore_signal、dispatch_semaphore_wait等待数据返回
//https同步请求 - (NSDictionary *)sendSynchronousRequestWithType:(HttpRequstType)requestType URL:(NSString *)url parameters:(NSDictionary *)params { NSDictionary __block *resultDic; dispatch_semaphore_t disp = dispatch_semaphore_create(0); [self sendHttpRequestWithType:requestType URL:url parameters:params successBlock:^(NSDictionary *successDic) { NSLog(@"正在数据加载2"); resultDic = successDic; dispatch_semaphore_signal(disp); } faildBlock:^(NSError *error) { NSLog(@"正在数据加载3"); resultDic = @{@"error": error}; dispatch_semaphore_signal(disp); 4000 }]; NSLog(@"正在数据加载1"); dispatch_semaphore_wait(disp, DISPATCH_TIME_FOREVER); NSLog(@"数据加载完毕"); return resultDic; }
网络正常,打印的过程应该是
正在数据加载1 -> 正在数据加载2 -> 数据加载完毕
注意: 调用这个同步http请求不可以在主线程中,否则会造成卡死。需要单独开启一个线程进行数据请求
可以像下面这样
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //进行数据请求 });
参考:
GCD中信号量的介绍 http://blog.csdn.net/eduora_meimei/article/details/23129977
https证书验证 http://www.jianshu.com/p/31bcddf44b8d
iOS-https http://www.jianshu.com/p/4b5d2d47833d
相关文章推荐
- XMLHttpRequest的同步和异步请求
- ASIHTTPRequest系列(一):同步和异步请求
- NSMutableURLRequest Http 请求 同步 异步
- iOS 网络编程(HTTP 同步GET请求,同步POST请求,异步GET请求,异步POST请求)
- ASIHTTPRequest系列(一):同步和异步请求
- ASIHTTPRequest系列(一):同步和异步请求 .
- ASIHTTPRequest系列(一):同步和异步请求
- NSMutableURLRequest Http 请求 同步 异步
- ASIHTTPRequest系列(一):同步和异步请求
- ASIHTTP 框架,同步、 异步请求、 上传 、 下载
- ASIHTTPRequest系列(一):同步和异步请求
- ios ASIHttpLib 同步请求和异步请求
- Http同步和异步请求区别
- ASIHTTPRequest系列(一):同步和异步请求
- ASIHTTPRequest系列(一):同步和异步请求
- [转]IOS程序之HTTP同步请求与异步请求问题解决
- Http同步和异步请求区别
- iOS 网络编程(HTTP 同步GET请求,同步POST请求,异步GET请求,异步POST请求)
- ASIHTTPRequest系列(一):同步和异步请求
- 【Objective-C】Http常用API、同步请求与异步请求