一、NSURLSession概覽
1 NSURLSession的類型
- 默認(rèn)會(huì)話(Default Sessions)使用了持久的磁盤(pán)緩存,并且將用戶的證書(shū)存入鑰匙串
- 臨時(shí)會(huì)話(Ephemeral Sessions)沒(méi)有向磁盤(pán)中存入任何數(shù)據(jù),所有相關(guān)內(nèi)容都存在RAM中,當(dāng)會(huì)話無(wú)效時(shí),證書(shū)及緩存的數(shù)據(jù)都會(huì)被清除掉。
- 后臺(tái)會(huì)話(Background Sessions)除了使用了一個(gè)單獨(dú)的線程來(lái)處理會(huì)話之外,與默認(rèn)會(huì)話類似。但使用后臺(tái)會(huì)話有一些限制,比如會(huì)話必須提供事件交付的代理方法、只有HTTP和HTTPS協(xié)議支持后臺(tái)會(huì)話、總是伴隨著重定向。僅僅在上傳文件時(shí)才支持后臺(tái)會(huì)話,當(dāng)你上傳二進(jìn)制對(duì)象或者數(shù)據(jù)流時(shí)是不支持后臺(tái)會(huì)話的。當(dāng)App進(jìn)入后臺(tái)時(shí),后臺(tái)傳輸就會(huì)被初始化。(需要注意的是iOS8和OS X 10.10之前的版本中后臺(tái)會(huì)話是不支持?jǐn)?shù)據(jù)任務(wù)(data task)的)
會(huì)話的類型都要通過(guò)NSURLSessionConfiguration來(lái)指定
NSURLSessonConfiguration的創(chuàng)建
//默認(rèn)會(huì)話
NSURLSessionConfiguration* defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
//臨時(shí)會(huì)話
NSURLSessionConfiguration* ephemeralSessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
//后臺(tái)會(huì)話
NSURLSessionConfiguration* backgroundSessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"bacjgroundID"];
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
2 NSURLSession的各種任務(wù)
在一個(gè)Session會(huì)話中可以發(fā)起的任務(wù)分為三種:數(shù)據(jù)任務(wù)(Data task),下載任務(wù)(Download task),上傳任務(wù)(Upload task)。
- Data Task(數(shù)據(jù)任務(wù))負(fù)責(zé)使用NSData對(duì)象來(lái)發(fā)送和接收數(shù)據(jù)。Data Task是為了那些簡(jiǎn)短的并且經(jīng)常從服務(wù)器請(qǐng)求的數(shù)據(jù)而準(zhǔn)備的。該任務(wù)可以沒(méi)請(qǐng)求一次就對(duì)返回的數(shù)據(jù)進(jìn)行一次處理。
- Download task(下載任務(wù))以表單的形式接收一個(gè)文件的數(shù)據(jù),該任務(wù)支持后臺(tái)下載。
- Upload task(上傳任務(wù))以表單的形式上傳一個(gè)文件的數(shù)據(jù),該任務(wù)同樣支持后臺(tái)下載。
二.RUL編碼
1 概述
1.URL編碼概述
無(wú)論是GET、POST還是其他的請(qǐng)求,與服務(wù)器交互的URL是需要進(jìn)行編碼的。因?yàn)檫M(jìn)行URL編碼的參數(shù)服務(wù)器那邊才能進(jìn)行解析,為了能和服務(wù)器正常的交互,我們需要對(duì)我們的參數(shù)進(jìn)行轉(zhuǎn)義和編碼。先簡(jiǎn)單的聊一下什么是URL吧,其實(shí)URL是URI(Uniform Resource Identifier ---- 統(tǒng)一資源定位符)的一種。URL就是互聯(lián)網(wǎng)上資源的地址,用戶可以通過(guò)URL來(lái)找到其想訪問(wèn)的資源。RFC3986文檔規(guī)定,<font color = red>Url中只允許包含英文字母(a-zA-Z)、數(shù)字(0-9)、-_.~4個(gè)特殊字符以及所有保留字符,</font>如果你的URL中含有漢字,那么就需要對(duì)其進(jìn)行轉(zhuǎn)碼了。<font color = red>RFC3986中指定了以下字符為保留字符:! * ' ( ) ; : @ & = + $ , / ? # [ ]。</font>
在URL編碼時(shí)有一定的規(guī)則,在Get請(qǐng)求中Query是存放在URL后邊,而在POST中是放在Request的Body中。如果你的參數(shù)只是一個(gè)<font color = red>key-Value</font>, 那么Query的形式就是key = value。如果你的參數(shù)是一個(gè)數(shù)組比如<font color = red>key = [itme1, item2, item3,……]</font>,那么你的Query的格式就是<font color = red>key[]=item1&key[itme2]&key[item3]……</font>。如果你的參數(shù)是一個(gè)字典比如<font color = red>key = ["subKey1":"item1", "subKey2":"item2"]</font>, 那么Query對(duì)應(yīng)的形式就是<font color = red>key[subKey1]=item1&key[subKey2]=item2</font>.接下來(lái)我們要做的就是將字典進(jìn)行URL編碼。
2.編碼
AFNetworking中對(duì)應(yīng)的編碼如下:
NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValue]];
}
return [mutablePairs componentsJoinedByString:@"&"];
}
NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) {
return AFQueryStringPairsFromKeyAndValue(nil, dictionary);
}
NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = value;
// Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
id nestedValue = dictionary[nestedKey];
if (nestedValue) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
}
}
} else if ([value isKindOfClass:[NSArray class]]) {
NSArray *array = value;
for (id nestedValue in array) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
}
} else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
}
} else {
[mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
}
return mutableQueryStringComponents;
}
三、數(shù)據(jù)任務(wù)--NSURLSesionDataTask
NSURLSessionDataTask的使用步驟
- 首先我們先創(chuàng)建會(huì)話使用的URL,在創(chuàng)建URL是我們要對(duì)parameters字典參數(shù)進(jìn)行URL編碼。如果是GET方式的請(qǐng)求的話就使用?號(hào)將我們編碼后的字符串拼接到URL后方即可。
- 然后創(chuàng)建我們會(huì)話使用的請(qǐng)求(NSURLMutableRequest),在創(chuàng)建請(qǐng)求時(shí)我們要指定請(qǐng)求方式是POST還是GET。如果是POST方式,我們就將編碼后的URL字符串放入request的HTTPBody中即可,有一點(diǎn)需要注意的是我們傳輸?shù)臄?shù)據(jù)都是二進(jìn)制的,所以在將字符串存入HTTPBody之前要將其轉(zhuǎn)換成二進(jìn)制,在轉(zhuǎn)換成二進(jìn)制的同時(shí)我們使用的是UTF8這種編碼格式。
- 創(chuàng)建完Request后,我們就該創(chuàng)建URLSession了,此處我們?yōu)榱撕?jiǎn)單就獲取了全局的Session單例。我們使用這個(gè)Session單例創(chuàng)建了含有Request對(duì)象的一個(gè)DataTask。在這個(gè)DataTask創(chuàng)建時(shí),有一個(gè)尾隨閉包,這個(gè)尾隨閉包用來(lái)接收服務(wù)器返回來(lái)的數(shù)據(jù)。當(dāng)然此處可以指定代理,使用代理來(lái)接收和解析數(shù)據(jù)的,稍后會(huì)介紹到。
- 最后切記創(chuàng)建好的Data Task是處于掛起狀態(tài)的,需要你去喚醒它,所以我們要調(diào)用dataTask的resume方法進(jìn)行喚醒。具體如下所示。
NSString* baseUrlStr = [NSString stringWithUTF8String:"www.baidu.com"];
NSURL* url = [NSURL URLWithString:baseUrlStr];
NSMutableURLRequest* mutableRequest = [NSMutableURLRequest requestWithURL:url];
//設(shè)置請(qǐng)求方式
mutableRequest.HTTPMethod = @"GET";
//參數(shù)編碼
//拼接參數(shù)
//get 用 ?
//post httpbody
//創(chuàng)建data task
NSURLSessionDataTask* dataTask = [self.session dataTaskWithRequest:mutableRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
//喚起
[dataTask resume];
四、上傳任務(wù) --- Upload Task
NSURLSessionUploadTask的使用步驟:
- 先創(chuàng)建URL和request并為request指定請(qǐng)求方式為POST
- 然后創(chuàng)建Session,此處我們使用SessionConfiguration為Session的類型指定為default session類型。并為該Session指定代理對(duì)象為self。
- 最后使用Session來(lái)創(chuàng)建upload task,在創(chuàng)建upload task時(shí)為上傳任務(wù)指定NSURLRequest對(duì)象,并且傳入要上傳的表單數(shù)據(jù)formData,當(dāng)然不要忘了將任務(wù)進(jìn)行喚醒。
NSString* baseUrlStr = [NSString stringWithUTF8String:"www.baidu.com"];
NSURL* url = [NSURL URLWithString:baseUrlStr];
NSMutableURLRequest* mutableRequest = [NSMutableURLRequest requestWithURL:url];
//設(shè)置請(qǐng)求方式
mutableRequest.HTTPMethod = @"POST";
//參數(shù)編碼
//拼接參數(shù)
//post httpbody
//上傳文件的數(shù)據(jù)
NSString* uploadStr = @"this is a upload str";
NSData* uploadData = [uploadStr dataUsingEncoding:NSUTF8StringEncoding];
NSURLSessionUploadTask* uploadTask = [self.session uploadTaskWithRequest:mutableRequest fromData:uploadData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
}];
//喚醒
[uploadTask resume];
備注:
在上傳文件時(shí),如果你想時(shí)刻的監(jiān)聽(tīng)上傳的進(jìn)度,你可以去實(shí)現(xiàn)NSURLSessionTaskDelegate中的didSendBodyData方法,該方法會(huì)實(shí)時(shí)的監(jiān)聽(tīng)文件上傳的速度。
bytesSent回調(diào)參數(shù)表示本次上傳的字節(jié)數(shù),
totalBytesSend回調(diào)參數(shù)表示已經(jīng)上傳的數(shù)據(jù)大小,totalBytesExpectedToSend表示文件公有的大小。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
五、下載任務(wù)--Download Task
1.創(chuàng)建后臺(tái)會(huì)話
NSURLSessionConfiguration* backgroundSessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"bacjgroundID"];
self.session = [NSURLSession sessionWithConfiguration:backgroundSessionConfiguration delegate:self delegateQueue:queue];
2.開(kāi)始下載
NSURLSessionConfiguration* backgroundSessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"bacjgroundID"];
self.session = [NSURLSession sessionWithConfiguration:backgroundSessionConfiguration delegate:self delegateQueue:nil];
if (self.resumeData) {
//如果有已下載的數(shù)據(jù)
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//Block下載方式不適合大文件下載
//接收數(shù)據(jù)
//確定文件路徑
//剪切文件
}];
}else{
//沒(méi)下載過(guò)
NSString* baseUrlStr = [NSString stringWithUTF8String:"www.baidu.com"];
NSURL* url = [NSURL URLWithString:baseUrlStr];
NSMutableURLRequest* mutableRequest = [NSMutableURLRequest requestWithURL:url];
//設(shè)置請(qǐng)求方式
mutableRequest.HTTPMethod = @"POST";
//參數(shù)編碼
//拼接參數(shù)
//post httpbody
//上傳文件的數(shù)據(jù)
NSString* uploadStr = @"this is a upload str";
NSData* uploadData = [uploadStr dataUsingEncoding:NSUTF8StringEncoding];
self.downloadTask = [self.session downloadTaskWithRequest:mutableRequest completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//Block下載方式不適合大文件下載
//接收數(shù)據(jù)
//確定文件路徑
//剪切文件
}];
}
[self.downloadTask resume];
推薦使用代理方法來(lái)處理下載
3.下載的暫停與恢復(fù)
//取消下載(不可以恢復(fù))
- (void)cancleDownLoad
{
[self.downloadTask cancel];
}
//可以恢復(fù)下載
- (void)cancleByResumeData
{
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
self.resumeData = resumeData;
}];
}
//掛起下載
- (void)suspendDownLoad
{
[self.downloadTask suspend];
}
//回復(fù)繼續(xù)下載
- (void)resumeDownLoad
{
[self.downloadTask resume];
}
4.下載任務(wù)的回調(diào)
NSURLSessionDownloadDelegate中的方法
/**
下載完成
@param session session對(duì)象
@param downloadTask downloadTask對(duì)象
@param location 臨時(shí)文件的下載目錄
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
//臨時(shí)文件在下載完成之后如果你不做任何處理的話,那么就會(huì)被自動(dòng)刪除
//創(chuàng)建文件存儲(chǔ)路徑
//移動(dòng)臨時(shí)文件
}
/**
下載文件偏移,主要用于斷點(diǎn)續(xù)傳
@param session session對(duì)象
@param downloadTask downloadTask對(duì)象
@param fileOffset 已經(jīng)下載文件的大小
@param expectedTotalBytes 文件的總大小
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
//更新下載進(jìn)度條
}
/**
實(shí)時(shí)監(jiān)聽(tīng)下載任務(wù)回調(diào)
@param session session對(duì)象
@param downloadTask downloadTask對(duì)象
@param bytesWritten 本次下載的數(shù)據(jù)
@param totalBytesWritten 已經(jīng)下載的數(shù)據(jù)總量
@param totalBytesExpectedToWrite 文件的總量
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//更新下載進(jìn)度條
}
//后臺(tái)下載完成之后的操作
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
//配合application:handleEventsForBackgroundURLSession:completionHandler:方法使用
}
//當(dāng)NSURLSession在后臺(tái)開(kāi)啟幾個(gè)任務(wù)之后, 如果有其他幾個(gè)任務(wù)完成后系統(tǒng)會(huì)調(diào)用應(yīng)用程序的
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
}
NSURLSessionTaskDelegate中的方法
//任務(wù)完成 不管是不是下載都會(huì)調(diào)用
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
}
六、網(wǎng)絡(luò)緩存
網(wǎng)絡(luò)緩存在網(wǎng)絡(luò)請(qǐng)求中使用的還是蠻多的,尤其是加載一些H5頁(yè)面時(shí)經(jīng)常會(huì)加一些緩存來(lái)提高用戶體驗(yàn)。有時(shí)的一些數(shù)據(jù)也會(huì)進(jìn)行緩存,你可將數(shù)據(jù)緩存到你的SQLite數(shù)據(jù)庫(kù)、PList文件,或者直接使用NSURLSession相關(guān)的東西進(jìn)行緩存。
1、緩存策略
在配置網(wǎng)絡(luò)請(qǐng)求緩存時(shí),有著不同的請(qǐng)求緩存策略。下方就是所有支持的網(wǎng)絡(luò)緩存策略:
- NSURLRequestUseProtocolCachePolicy -- 緩存存在就讀緩存,若不存在就請(qǐng)求服務(wù)器
- NSURLRequestReloadIgnoringLocalCacheData -- 忽略緩存,直接請(qǐng)求服務(wù)器數(shù)據(jù)
- NSURLRequestReturnCacheDataElseLoad -- 本地如有緩存就使用,忽略其有效性,無(wú)則請(qǐng)求服務(wù)器
- NSURLRequestReturnCacheDataDontLoad -- 直接加載本地緩存,沒(méi)有也不請(qǐng)求網(wǎng)絡(luò)
- NSURLRequestReloadIgnoringLocalAndRemoteCacheData -- 尚未實(shí)現(xiàn)
- NSURLRequestReloadRevalidatingCacheData -- 尚未實(shí)現(xiàn)
2、NSMutableURLRequest指定緩存策略
mutableRequest.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData
緩存目錄默認(rèn)為~/Library/Caches/[Boundle ID]/fsCachedData/緩存文件
3、NSURLSessionConfiguration指定緩存策略
SessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
4、NSURLCache + request進(jìn)行緩存
NSInteger memoryCapacity = 4 * 1024 * 1024;
NSInteger diskCapacity = 10 * 1024 * 1024;
NSString* cacheFilePath = @"myCache";
NSURLCache* urlCache = [[NSURLCache alloc] initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:cacheFilePath];
[NSURLCache setSharedURLCache:urlCache];
有一點(diǎn)需要注意的是此處設(shè)置的緩存路徑是相對(duì)于/Library/Caches/[Boundle ID]/的
5、NSURLCache +SessionConfiguration進(jìn)行緩存
SessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringCacheData;
NSInteger memoryCapacity = 4 * 1024 * 1024;
NSInteger diskCapacity = 10 * 1024 * 1024;
NSString* cacheFilePath = @"myCache";
NSURLCache* urlCache = [[NSURLCache alloc] initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:cacheFilePath];
SessionConfiguration.URLCache = urlCache;
6、清除緩存
NSFileManager removeItemAtPath
七、請(qǐng)求認(rèn)證
1.認(rèn)證方式
- NSURLAuthenticationMethodHTTPBasic: HTTP基本認(rèn)證,需要提供用戶名和密碼
- NSURLAuthenticationMethodHTTPDigest: HTTP數(shù)字認(rèn)證,與基本認(rèn)證相似需要用戶名和密碼
- NSURLAuthenticationMethodHTMLForm: HTML表單認(rèn)證,需要提供用戶名和密碼
- NSURLAuthenticationMethodNTLM: NTLM認(rèn)證,NTLM(NT LAN Manager)是一系列旨向用戶提供認(rèn)證,完整性和機(jī)密性的微軟安全協(xié)議
- NSURLAuthenticationMethodNegotiate: 協(xié)商認(rèn)證
- NSURLAuthenticationMethodClientCertificate: 客戶端認(rèn)證,需要客戶端提供認(rèn)證所需的證書(shū)
- NSURLAuthenticationMethodServerTrust: 服務(wù)端認(rèn)證,由認(rèn)證請(qǐng)求的保護(hù)空間提供信任
后兩個(gè)就是我們?cè)谡?qǐng)求HTTPS時(shí)會(huì)遇到的認(rèn)證,需要服務(wù)器或者客戶端來(lái)提供認(rèn)證的,這個(gè)證書(shū)就是我們平時(shí)常說(shuō)的CA證書(shū).
2.認(rèn)證處理策略
當(dāng)我們進(jìn)行網(wǎng)絡(luò)求時(shí),會(huì)對(duì)相應(yīng)的認(rèn)證做出響應(yīng)。在NSURLSession進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí)支持四種證書(shū)處理策略,這些認(rèn)證處理策略以枚舉的形式來(lái)存儲(chǔ),枚舉的類型為NSURLSessionAuthChallengeDisposition。下方就是認(rèn)證的所有處理策略:
- NSURLSessionAuthChallengeUseCredential 使用證書(shū)
- NSURLSessionAuthChallengePerformDefaultHandling 執(zhí)行默認(rèn)處理, 類似于該代理沒(méi)有被實(shí)現(xiàn)一樣,credential參數(shù)會(huì)被忽略
- NSURLSessionAuthChallengeCancelAuthenticationChallenge 取消請(qǐng)求,credential參數(shù)同樣會(huì)被忽略
- NSURLSessionAuthChallengeRejectProtectionSpace 拒絕保護(hù)空間,重試下一次認(rèn)證,credential參數(shù)同樣會(huì)被忽略
3.HTTPS請(qǐng)求證書(shū)處理
發(fā)起上述https請(qǐng)求后,就會(huì)執(zhí)行下方的代理方法。下方的委托代理方法屬于NSURLSessionDelegate中處理認(rèn)證的方法,也就是如果服務(wù)器需要認(rèn)證時(shí)就會(huì)執(zhí)行下方的回調(diào)方法。下方代碼首先從授權(quán)質(zhì)疑的保護(hù)空間中取出認(rèn)證方式,然后根據(jù)不同的認(rèn)證方式進(jìn)行不同的處理。下方給出了兩種認(rèn)證方式的處理,上面的if語(yǔ)句塊賦值服務(wù)端認(rèn)證,下面的if語(yǔ)句塊負(fù)責(zé)HTTP的基本認(rèn)證。具體處理方式如下所示。有一點(diǎn)需要注意的是如果在該委托回調(diào)方法中如果不執(zhí)行completionHandler閉包,那么認(rèn)證就會(huì)失效,是請(qǐng)求不到數(shù)據(jù)的。
/**
服務(wù)器需要驗(yàn)證時(shí)會(huì)觸發(fā)
@param session session對(duì)象
@param challenge 授權(quán)質(zhì)疑
@param completionHandler block
*/
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler {
// 判斷是否是信任服務(wù)器證書(shū)
if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
//https
// 告訴服務(wù)器,客戶端信任證書(shū)
// 創(chuàng)建憑據(jù)對(duì)象
NSURLCredential *credntial = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
// 通過(guò)completionHandler告訴服務(wù)器信任證書(shū)
completionHandler(NSURLSessionAuthChallengeUseCredential,credntial);
}
/**
* HTTP BASE
*/
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodHTTPBasic) {
NSURLCredential *credntial = [[NSURLCredential alloc] initWithUser:@"username" password:@"password" persistence:NSURLCredentialPersistenceForSession];
completionHandler(NSURLSessionAuthChallengeUseCredential,credntial);
}
//取消請(qǐng)求
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,nil);
}
八、NSURLSession相關(guān)代理
1、NSURLSessionDelegate
- didReceiveChallenge
其他
//Session無(wú)效后被調(diào)用
- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error
{
}
//后臺(tái)Session在執(zhí)行完后臺(tái)任務(wù)后所執(zhí)行的方法
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
}
2、NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler;
{
}
3、NSURLSessionDataDelegate
NSURLSessionDataDelegate中的方法主要是用來(lái)處理Data Task任務(wù)相應(yīng)的事件的
1、相應(yīng)處理策略
- NSURLSessionResponseCancel 取消數(shù)據(jù)的加載,默認(rèn)為 Cancel。此處理方式就是忽略數(shù)據(jù)的加載,取消對(duì)響應(yīng)數(shù)據(jù)的進(jìn)一步解析
- NSURLSessionResponseAllow 允許繼續(xù)操作, 會(huì)執(zhí)行 NSURLSessionDataDelegate中的dataTaskDidReceiveData回調(diào)方法
- NSURLSessionResponseBecomeDownload 將Data Task的響應(yīng)轉(zhuǎn)變?yōu)镈ownloadTask,會(huì)執(zhí)行NSURLSessionDownloadDelegate代理中相應(yīng)的方法
- NSURLSessionResponseBecomeStream 將Data Task的響應(yīng)轉(zhuǎn)變?yōu)镈ownloadTask,會(huì)執(zhí)行NSURLSessionStreamDelegate代理中相應(yīng)的方法
2.代理方法
/**
收到響應(yīng)時(shí)會(huì)執(zhí)行的方法
@param session session
@param dataTask dataTask
@param response 服務(wù)器響應(yīng)
@param completionHandler block
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
//處理策略設(shè)置成Allow后會(huì)執(zhí)行下方的方法,如果響應(yīng)處理策略不是Allow那么就不會(huì)接收到服務(wù)器的Data
}
/**
接收數(shù)據(jù)后會(huì)執(zhí)行的方法
@param session session
@param dataTask dataTask
@param data 接收的數(shù)據(jù)
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
}
/**
任務(wù)轉(zhuǎn)變?yōu)橄螺d時(shí)所執(zhí)行的方法
@param session session
@param dataTask dataTask
@param downloadTask downloadTask
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
{
}
/**
任務(wù)轉(zhuǎn)變?yōu)閟treamTask時(shí)所執(zhí)行的方法
@param session session
@param dataTask dataTask
@param streamTask streamTask
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didBecomeStreamTask:(NSURLSessionStreamTask *)streamTask
{
//iOS9
}
/**
將要進(jìn)行緩存時(shí)執(zhí)行的方法
@param session session
@param dataTask dataTask
@param proposedResponse streamTask
@param completionHandler block
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler
{
}