IOS开发系列——NSUrlSession专题
NSUrlSession专题
1概述
【主要参考】NSURLSession
http://blog.csdn.net/qq_29846663/article/details/68961167
NSURLSession在2013年随着iOS7的发布一起面世,苹果对它的定位是作为NSURLConnection的替代者,然后逐步将NSURLConnection退出历史舞台。现在使用最广泛的第三方网络框架:AFNetworking、SDWebImage等等都使用了NSURLSession。
在WWDC 2013中,Apple的团队对NSURLConnection进行了重构,并推出了NSURLSession作为替代。NSURLSession将NSURLConnection替换为NSURLSession和NSURLSessionConfiguration,以及3个NSURLSessionTask的子类:NSURLSessionDataTask,NSURLSessionUploadTask,和NSURLSessionDownloadTask。
它们之间的关系如下图:
NSURLSessionTask及三个子类继承关系:
NSURLSessionDataTask:主要用于读取服务端的简单数据,比如JSON数据。
NSURLSessionDownloadTask:这个task的主要用途是进行文件下载,它针对大文件的网络请求做了更多的处理,比如下载进度,断点续传等等。
NSURLSessionUploadTask:和下载任务对应,这个task主要是用于对服务端发送文件类型的数据使用的。
1.1NSURLSession的使用
NSURLSession本身是不会进行请求的,而是通过创建task的形式进行网络请求(resume()方法的调用),同一个NSURLSession可以创建多个task,并且这些task之间的cache和cookie是共享的。NSURLSession的使用有如下几步:
•第一步:创建NSURLSession对象
•第二步:使用NSURLSession对象创建Task
•第三步:启动任务
1.1.1创建NSURLSession对象
NSURLSession对象的创建有如下三种方法:
(1)直接创建
NSURLSession *session=[NSURLSessionsharedSession];
(2)配置后创建
[NSURLSessionsessionWithConfiguration:defaultSessionConfiguration];
(3)设置加代理获得
//使用代理方法需要设置代理,但是session的delegate属性是只读的,要想设置代理只能通过这种方式创建session
NSURLSession *session=[NSURLSessionsessionWithConfiguration:[NSURLSessionConfigurationdefaultSessionConfiguration]
delegate:self
delegateQueue:[[NSOperationQueuealloc]init]];
关于NSURLSession的配置有三种类型:
//默认的配置会将缓存存储在磁盘上
+(NSURLSessionConfiguration*)defaultSessionConfiguration;
//瞬时会话模式不会创建持久性存储的缓存
+(NSURLSessionConfiguration*)ephemeralSessionConfiguration;
//后台会话模式允许程序在后台进行上传下载工作
+(NSURLSessionConfiguration*)backgroundSessionConfigurationWithIdentifier:(NSString*)identifier
1.1.2使用NSURLSession对象创建Task
NSURLSessionTask的创建要根据具体需要创建相应类型的Task。
(1)NSURLSessionDataTask
通过request对象或url创建:
-(NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;
-(NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;
通过request对象或url创建,同时指定任务完成后通过completionHandler指定回调的代码块:
-(NSURLSessionDataTask*)dataTaskWithRequest:(NSURLRequest*)requestcompletionHandler:(void(^)(NSData*data,NSURLResponse*response,NSError*error))completionHandler;
-(NSURLSessionDataTask*)dataTaskWithURL:(NSURL*)urlcompletionHandler:(void(^)(NSData*data,NSURLResponse*response,NSError*error))completionHandler;
(2)NSURLSessionUploadTask
通过request创建,在上传时指定文件源或数据源:
-(NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)requestfromFile:(NSURL *)fileURL;
-(NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)requestfromData:(NSData *)bodyData;
-(NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request;
通过completionHandler指定任务完成后的回调代码块:
-(NSURLSessionUploadTask*)uploadTaskWithRequest:(NSURLRequest*)requestfromFile:(NSURL*)fileURLcompletionHandler:(void(^)(NSData*data,NSURLResponse*response,NSError*error))completionHandler;
-(NSURLSessionUploadTask*)uploadTaskWithRequest:(NSURLRequest*)requestfromData:(NSData*)bodyDatacompletionHandler:(void(^)(NSData*data,NSURLResponse*response,NSError*error))completionHandler;
(3)NSURLSessionDownloadTask
下载任务支持断点续传,第三种方式是通过之前已经下载的数据来创建下载任务:
-(NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request;
-(NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url;
-(NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;
同样地可以通过completionHandler指定任务完成后的回调代码块:
-(NSURLSessionDownloadTask*)downloadTaskWithRequest:(NSURLRequest*)requestcompletionHandler:(void(^)(NSURL*location,NSURLResponse*response,NSError*error))completionHandler;
-(NSURLSessionDownloadTask*)downloadTaskWithURL:(NSURL*)urlcompletionHandler:(void(^)(NSURL*location,NSURLResponse*response,NSError*error))completionHandler;
-(NSURLSessionDownloadTask*)downloadTaskWithResumeData:(NSData*)resumeDatacompletionHandler:(void(^)(NSURL*location,NSURLResponse*response,NSError*error))completionHandler;
我们在使用三种task的任意一种的时候都可以指定相应的代理。NSURLSession的代理对象结构如下:
NSURLSessionDelegate–作为所有代理的基类,定义了网络请求最基础的代理方法。
NSURLSessionTaskDelegate–定义了网络请求任务相关的代理方法。
NSURLSessionDownloadDelegate–用于下载任务相关的代理方法,比如下载进度等等。
NSURLSessionDataDelegate–用于普通数据任务和上传任务。
相信大家都会使用代理,具体的使用方法这里不再讲解。
1.1.3启动任务
//启动任务
[taskresume];
1.2GET请求与POST请求
我们可以使用NSURLSessionDataTask进行GET请求与POST请求。
1.2.1GET请求
//1、创建NSURLSession对象
NSURLSession*session=[NSURLSessionsharedSession];
//2、利用NSURLSession创建任务(task)
NSURL*url=[NSURLURLWithString:@"http://www.xxx.com/login?username=myName&pwd=myPsd"];
NSURLSessionDataTask*task=[sessiondataTaskWithURL:urlcompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
}];
//3、执行任务
[taskresume];
1.2.2POST请求
//1、创建NSURLSession对象
NSURLSession *session= [NSURLSession sharedSession];
//2、利用NSURLSession创建任务(task)
NSURL *url = [NSURLURLWithString:@"http://www.xxx.com/login"];
//创建请求对象里面包含请求体
NSMutableURLRequest*request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod =@"POST";
request.HTTPBody =[@"username=myName&pwd=myPsd"dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionDataTask*task = [session dataTaskWithRequest:request completionHandler:^(NSData *_Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error){
//打印解析后的json数据
//NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
//3、执行任务
[task resume];
1.3文件的上传
我们可以使用NSURLSessionUploadTask进行文件的上传,使用NSURLSessionUploadTask文件上传共有两种方法:
方法1:
NSURLSessionUploadTask *task=[[NSURLSessionsharedSession]uploadTaskWithRequest:requestfromFile:filename completionHandler:^(NSData*data,NSURLResponse*response,NSError*error){
}];
方法2:
[self.session uploadTaskWithRequest:request fromData:bodycompletionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"-------%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
}];
1.3.1以数据流的方式进行上传
这种方式好处就是大小不受限制,示例代码如下:
-(void)NSURLSessionBinaryUploadTaskTest{
//1.创建url
NSString*urlString=@"http://www.xxxx.com/upload.php";
//urlString = [urlStringstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSetURLFragmentAllowedCharacterSet]];
NSURL*url=[NSURLURLWithString:urlString];
//2.创建请求
NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:url];
//文件上传使用post
request.HTTPMethod=@"POST";
//3.开始上传request的body data将被忽略,而由fromData提供
[[[NSURLSessionsharedSession]uploadTaskWithRequest:requestfromData:[NSDatadataWithContentsOfFile:@"/Users/lifengfeng/Desktop/test.jpg"]completionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
if(error==nil){
NSLog(@"uploadsuccess:%@",[[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding]);
}else{
NSLog(@"uploaderror:%@",error);
}
}] resume];
}
1.3.2以拼接表单的方式进行上传
上传的关键是请求体部分的表单拼接,获取本地上传文件的类型(MIME Types),至于具体的网络上传则很简单。另外拼接表单的方式会有大小限制,即HTML的MAX_FILE_SIZE限制(可以自己设定,一般2MB)。
根据上面的继承关系图,我们知道uploadTask是dataTask的子类,也可以使用uploadTask来代替dataTask。
表单拼接格式如下,boundary作为分界线:
--boundary
Content-Disposition:form-data;name=”表单控件名称”;filename=”上传文件名称”
Content-Type:要上传文件MIME Types
要上传文件二进制数据;
--boundary--
示例代码如下:
-(void)NSURLSessionUploadTaskTest{
//1.创建url采用Apache本地服务器
NSString*urlString=@"http://localhost/upload/upload.php";
urlString=[urlStringstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSetURLFragmentAllowedCharacterSet]];
NSURL*url=[NSURLURLWithString:urlString];
//2.创建请求
NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:url];
//文件上传使用post
request.HTTPMethod=@"POST";
NSString*contentType=[NSStringstringWithFormat:@"multipart/form-data;boundary=%@",@"boundary"];
[requestsetValue:contentTypeforHTTPHeaderField:@"Content-Type"];
//test.jpg
//3.拼接表单,大小受MAX_FILE_SIZE限制(2MB)FilePath:要上传的本地文件路径formName:表单控件名称,应于服务器一致
NSData*data=[selfgetHttpBodyWithFilePath:@"/Users/lifengfeng/Desktop/test.jpg"formName:@"file"reName:@"newName.png"];
request.HTTPBody=data;
//根据需要是否提供,非必须,如果不提供,session会自动计算
[requestsetValue:[NSStringstringWithFormat:@"%lu",data.length]forHTTPHeaderField:@"Content-Length"];
//4.1使用dataTask
[[[NSURLSessionsharedSession]dataTaskWithRequest:requestcompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
if(error==nil){
NSLog(@"uploadsuccess:%@",[[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding]);
}else{
NSLog(@"uploaderror:%@",error);
}
}]resume];
#if 0
//4.2开始上传使用uploadTaskfromData:可有可无,会被忽略
[[[NSURLSessionsharedSession]uploadTaskWithRequest:requestfromData:nilcompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
if(error==nil){
NSLog(@"uploadsuccess:%@",[[NSStringalloc]initWithData:dataencoding:NSUTF8StringEncoding]);
}else{
NSLog(@"uploaderror:%@",error);
}
}]resume];
#endif
}
其中用到的两个自定义的方法:
///
filePath:要上传的文件路径formName:表单控件名称reName:上传后文件名
-(NSData *)getHttpBodyWithFilePath:(NSString *)filePath formName:(NSString*)formName reName:(NSString *)reName
{
NSMutableData *data = [NSMutableData data];
NSURLResponse *response = [selfgetLocalFileResponse:filePath];
//文件类型:MIMEType文件的大小:expectedContentLength文件名字:suggestedFilename
NSString *fileType = response.MIMEType;
//如果没有传入上传后文件名称,采用本地文件名!
if (reName == nil) {
reName = response.suggestedFilename;
}
//表单拼接
NSMutableString *headerStrM=[NSMutableString string];
[headerStrMappendFormat:@"--%@\r\n",@"boundary"];
// name:表单控件名称filename:上传文件名
[headerStrMappendFormat:@"Content-Disposition: form-data; name=%@;filename=%@\r\n",formName,reName];
[headerStrMappendFormat:@"Content-Type: %@\r\n\r\n",fileType];
[data appendData:[headerStrM dataUsingEncoding:NSUTF8StringEncoding]];
//文件内容
NSData *fileData = [NSDatadataWithContentsOfFile:filePath];
[data appendData:fileData];
NSMutableString *footerStrM =[NSMutableStringstringWithFormat:@"\r\n--%@--\r\n",@"boundary"];
[dataappendData:[footerStrMdataUsingEncoding:NSUTF8StringEncoding]];
//NSLog(@"dataStr=%@",[[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding]);
return data;
}
///获取响应,主要是文件类型和文件名
-(NSURLResponse *)getLocalFileResponse:(NSString *)urlString
{
urlString = [urlStringstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSetURLFragmentAllowedCharacterSet]];
//本地文件请求
NSURL *url = [NSURLfileURLWithPath:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
__block NSURLResponse *localResponse = nil;
//使用信号量实现NSURLSession同步请求
dispatch_semaphore_t semaphore =dispatch_semaphore_create(0);
[[[NSURLSession sharedSession]dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data,NSURLResponse * _Nullable response, NSError * _Nullable error) {
localResponse = response;
dispatch_semaphore_signal(semaphore);
}] resume];
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
returnlocalResponse;
}
1.4文件的下载
我们可以使用NSURLSessionDownloadTask实现文件的下载。NSURLSession使用代理方法也可以实现大文件下载,但是它实现不了断点下载,所以一般不用。
-(void)NSURLSessionDownloadTaskTest{
//1.创建url
NSString*urlString=[NSStringstringWithFormat:@"http://www.xxx.com/test.mp3"];
//一些特殊字符编码
urlString=[urlStringstringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSetURLQueryAllowedCharacterSet]];
NSURL*url=[NSURLURLWithString:urlString];
//2.创建请求
NSURLRequest*request=[NSURLRequestrequestWithURL:url];
//3.创建会话,采用苹果提供全局的共享session
NSURLSession*sharedSession=[NSURLSessionsharedSession];
//4.创建任务
NSURLSessionDownloadTask*downloadTask=[sharedSessiondownloadTaskWithRequest:requestcompletionHandler:^(NSURL*_Nullablelocation,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
if(error==nil){
//location:下载任务完成之后,文件存储的位置,这个路径默认是在tmp文件夹下!
//只会临时保存,因此需要将其另存
NSLog(@"location:%@",location.path);
//采用模拟器测试,为了方便将其下载到Mac桌面
//NSString*filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask, YES) lastObject];
NSString*filePath=@"/Users/lifengfeng/Desktop/test.mp3";
NSError*fileError;
[[NSFileManagerdefaultManager]copyItemAtPath:location.pathtoPath:filePatherror:&fileError];
if(fileError==nil){
NSLog(@"filesave success");
}else{
NSLog(@"filesave error: %@",fileError);
}
}else{
NSLog(@"downloaderror:%@",error);
}
}];
//5.开启任务
[downloadTaskresume];
}
2NSUrlProtocol中URLSession使用
【主要参考】使用NSURLProtocol和NSURLSession拦截UIWebView的HTTP请求(包括ajax请求)
http://www.cnblogs.com/wobuyayi/p/6283599.html
注意:NSURLProtocol只能拦截UIWebView、NSURLConnection、NSURLSession和基于NSURLConnenction、NSURLSession实现的第三方框架(如AFNetworking)发出的网络请求,无法拦截WKWebview、CFNetwork以及基于CFNetwork实现的第三方框架(如MKNetworkit)发出的网络请求。
下面提供一个完整的NSURLProtocol的实现类:
RichURLSessionProtocol.h
#import@interfaceRichURLSessionProtocol : NSURLProtocol@end
RichURLSessionProtocol.m
#import "RichURLSessionProtocol.h"
static NSString * const RichURLProtocolHandledKey =@"RichURLProtocolHandledKey";
@interface RichURLSessionProtocol()
{
NSURLResponse* _urlResponse;
NSMutableData*_responseData;
}
@property (atomic,strong,readwrite) NSURLSessionDataTask *task;
@property (nonatomic,strong) NSURLSession *session;
@end
@implementation RichURLSessionProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
//只处理http和https请求
NSString *scheme = [[requestURL] scheme];
if ( ([schemecaseInsensitiveCompare:@"http"] == NSOrderedSame ||
[schemecaseInsensitiveCompare:@"https"] == NSOrderedSame))
{
//看看是否已经处理过了,防止无限循环
if ([NSURLProtocolpropertyForKey:RichURLProtocolHandledKey inRequest:request]) {
return NO;
}
return YES;
}
return NO;
}
+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
/**可以在此处添加头等信息*/
NSMutableURLRequest*mutableReqeust = [request mutableCopy];
return mutableReqeust;
}
- (void)startLoading
{
NSMutableURLRequest*mutableReqeust = [[self request] mutableCopy];
//打标签,防止无限循环
[NSURLProtocolsetProperty:@YES forKey:RichURLProtocolHandledKey inRequest:mutableReqeust];
NSURLSessionConfiguration*configure = [NSURLSessionConfiguration defaultSessionConfiguration];
NSOperationQueue *queue =[[NSOperationQueue alloc] init];
self.session= [NSURLSessionsessionWithConfiguration:configure delegate:self delegateQueue:queue];
self.task = [self.sessiondataTaskWithRequest:mutableReqeust];
[self.task resume];
}
- (void)stopLoading
{
[self.sessioninvalidateAndCancel];
self.session = nil;
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask*)task didCompleteWithError:(NSError *)error
{
if (error != nil) {
[self.clientURLProtocol:self didFailWithError:error];
}else
{
[self.clientURLProtocolDidFinishLoading:self];
}
}
- (void)URLSession:(NSURLSession *)sessiondataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse*)response
completionHandler:(void(^)(NSURLSessionResponseDisposition disposition))completionHandler
{
_urlResponse= response;
// Create space for containing incoming data
// This method may be called more than once if you're getting a multi-part
mime
// message and will be called once there's enough date to create the
response object
// Hence doa check if_responseData already there
_responseData= [[NSMutableDataalloc]init];
//NSLog(@"didReceiveResponse self: %@",self);
[self.clientURLProtocol:selfdidReceiveResponse:responsecacheStoragePolicy:NSURLCacheStorageNotAllowed];
completionHandler(NSURLSessionResponseAllow);
[self.client URLProtocol:selfdidReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
//接受数据回调,有可能有多次回调
- (void)URLSession:(NSURLSession *)sessiondataTask:(NSURLSessionDataTask *)dataTaskdidReceiveData:(NSData *)data
{
// Append the new data
[_responseDataappendData:data];
[self.clientURLProtocol:selfdidLoadData:data];
}
- (void)URLSession:(NSURLSession *)sessiondataTask:(NSURLSessionDataTask *)dataTask willCacheResponse: (NSCachedURLResponse*)proposedResponse completionHandler: (void (^)(NSCachedURLResponse *_Nullable)) completionHandler
{
completionHandler(proposedResponse);
}
//TODO:重定向
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask*)task willPerformHTTPRedirection:(NSHTTPURLResponse *)responsenewRequest:(NSURLRequest *)newRequest completionHandler:(void (^)(NSURLRequest*))completionHandler
{
NSMutableURLRequest*redirectRequest;
redirectRequest = [newRequestmutableCopy];
[[self class]removePropertyForKey:RichURLProtocolHandledKey inRequest:redirectRequest];
[[self client]URLProtocol:self wasRedirectedToRequest:redirectRequestredirectResponse:response];
[self.task cancel];
[[self client]URLProtocol:self didFailWithError:[NSError errorWithDomain:NSCocoaErrorDomaincode:NSUserCancelledError userInfo:nil]];
}
- (instancetype)initWithRequest:(NSURLRequest *)requestcachedResponse:(NSCachedURLResponse *)cachedResponseclient:(id)client
{
NSMutableURLRequest*redirectRequest;
redirectRequest = [requestmutableCopy];
//添加认证信息
NSString *authString =[[[NSString stringWithFormat:@"%@:%@", kGlobal.userInfo.sAccount,kGlobal.userInfo.sPassword] dataUsingEncoding:NSUTF8StringEncoding]base64EncodedString];
authString = [NSStringstringWithFormat: @"Basic %@", authString];
[redirectRequestsetValue:authString forHTTPHeaderField:@"Authorization"];
NSLog(@"拦截的请求:%@",request.URL.absoluteString);
self = [superinitWithRequest:redirectRequest cachedResponse:cachedResponse client:client];
if (self) {
// Some stuff
}
return self;
}
- (void)URLSession:(NSURLSession
*)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition,
NSURLCredential * _Nullable))completionHandler{
NSLog(@"自定义Protocol开始认证...");
NSString *authMethod =[[challenge protectionSpace] authenticationMethod];
NSLog(@"%@认证...",authMethod);
if([challenge.protectionSpace.authenticationMethodisEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSURLCredential *card =[[NSURLCredential alloc] initWithTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,card);
}
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM]){
if ([challengepreviousFailureCount] == 0) {
NSURLCredential*credential = [NSURLCredential credentialWithUser:kGlobal.userInfo.sAccountpassword:kGlobal.userInfo.sPassword persistence:NSURLCredentialPersistenceForSession];
[[challenge sender]useCredential:credential forAuthenticationChallenge:challenge];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}else{
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,nil);
}
}
NSLog(@"自定义Protocol认证结束");
//通用SSL认证法二:
//if ([challenge.protectionSpace.authenticationMethodisEqualToString:NSURLAuthenticationMethodServerTrust]) {
//NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
//completionHandler(NSURLSessionAuthChallengeUseCredential,card);
//[challenge.sender
useCredential:[NSURLCredential
credentialForTrust:challenge.protectionSpace.serverTrust]
forAuthenticationChallenge:challenge];
//}
}
@end
3参考链接
(Good)使用NSURLProtocol和NSURLSession拦截UIWebView的HTTP请求(包括ajax请求)
http://www.cnblogs.com/wobuyayi/p/6283599.html
从NSURLConnection到NSURLSession
ios NSURLSession(iOS7后,取代NSURLConnection)使用说明及后台工作流程分析
http://www.mobile-open.com/2015/92324.html
NSURLSession与NSURLConnection区别
http://www.cnblogs.com/kakaluote123/articles/5426923.html
HTTP协议授权访问
http://blog.csdn.net/yangtiang/article/details/22793215
NSURLCredential身份认证
http://blog.csdn.net/majiakun1/article/details/17013379
使用NSURLConnection连接HTTPS(SSL)站点