URLLoading System( 網(wǎng)絡(luò)資源加載)
Foundation框架中提供了資源網(wǎng)絡(luò)請(qǐng)求部分的基本組件,通過指定-URL(資源路徑)和TransformProtocol(傳輸協(xié)議),通過stream流實(shí)現(xiàn)數(shù)據(jù)的傳輸融欧。常見的傳輸協(xié)議主要有以下幾種:
*File Transfer Protocol (ftp://) 文件傳輸協(xié)議:常用作文件傳輸協(xié)議,公司內(nèi)部和局網(wǎng)內(nèi)常使用磨确。
*Hypertext Transfer Protocol (http://)超文本傳輸協(xié)議: 常用于瀏覽器中網(wǎng)絡(luò)請(qǐng)求
*Hypertext Transfer Protocol with encryption (https://)加密的超文本傳輸協(xié)議,就是在http的基礎(chǔ)上增加了C/S(服務(wù)器與客戶端)之間的認(rèn)證,
Local file URLs (file:///),本地資源傳輸協(xié)議,按照協(xié)議規(guī)定的格式從本地加載資源,其后指定的就是資源在本地的路徑,大家有沒有主意到這里有三條斜杠,因?yàn)樗械膮f(xié)議必須以 ://+ 主機(jī)地址或域名:端口號(hào) +/文件資源路徑或者是查詢語句。 此處是加載本地文件,所以中間的主機(jī)域名和端口號(hào)省略了就變成:///。
Data URLs (data://) 數(shù)據(jù)傳輸協(xié)議。
當(dāng)然除此之外你還可以定義自己的協(xié)議,比如蘋果的 sms:// 短信協(xié)議, prompt:// 庭惜,
- 例如當(dāng)我門要與HTML5做交互的時(shí)候,可以通過定義我門自己的協(xié)議頭 ourselfprotocol://+你需要攔截信息。 不熟悉的朋友請(qǐng)看UIWebView頭文件的代理方法穗酥。 通過截獲協(xié)議頭的scheme,我們就能快速的定位那些是需要我門攔截分析的URL了,當(dāng)然你也可以通過字符串進(jìn)行分割护赊。
+URL加載系統(tǒng)包括類加載URL以及一些重要的助手類,使用這些URL加載類修改他們的行為惠遏。助手類主要分為五類:協(xié)議支持,認(rèn)證和證書,cookie存儲(chǔ)、配置管理和緩存管理骏啰。Foundation中主要提供了如下幾個(gè)類用于網(wǎng)絡(luò)資源的加載.包括目前的很多主流框架如SDWebImage,AFNetWroking,都依賴這些類节吮。主要常用的還是NSURLConnection,NSURLSession,NSURL,NSURLRequest.
資源加載協(xié)議類NSURLProtocol
,
*從名字上很容易想到它是一個(gè)定義資源加載的協(xié)議,其實(shí)不然. 它屬于一個(gè)抽象的類判耕,定義了一些基本的方法,主要是機(jī)遇網(wǎng)絡(luò)請(qǐng)求資源加載的透绩。通常使用它的子類進(jìn)行擴(kuò)展,當(dāng)使用NSURLSession和NSURLConnection進(jìn)行網(wǎng)絡(luò)資源加載的時(shí)候,通常會(huì)去訪問NSURLClinetProtocol,即詢問請(qǐng)求方是否能夠處理這個(gè)請(qǐng)求,如果返回能則使用我門自定的子類進(jìn)行網(wǎng)絡(luò)資源加載,如果不能則使用系統(tǒng)默認(rèn)的方式進(jìn)行資源加載
//這是一個(gè)NSURLProtoclClient的對(duì)象,它就像一個(gè)鉤子 一樣,如果我們?nèi)绻贜SURLLoadingSystem詢問NSURlProtocol 的canInitWithRequest 方法時(shí)候,回答YES,則需要我們自己定義類去處理網(wǎng)絡(luò)請(qǐng)求,這個(gè)時(shí)候NSURLProtocolClient實(shí)例就是專門來幫我們處理網(wǎng)絡(luò)請(qǐng)求資源的回調(diào)的祈秕。之所以系統(tǒng)定義到這個(gè)類的屬性里,是為了我門在創(chuàng)建NSURLProtocol子類的時(shí)候,通過子類能夠狠方便的調(diào)用 NSURLProtocolClient的實(shí)例去處理網(wǎng)路資源的加載渺贤。
@property (nullable, readonly, retain) idclient;
//一個(gè)請(qǐng)求對(duì)象的實(shí)例對(duì)象雏胃,將我門訪問的URL資源路徑,請(qǐng)求頭中的一些參數(shù)進(jìn)行了統(tǒng)一的封裝,如 accept type,Content-Type,文件的編碼格式,壓縮方式,是否保持心跳連接,是否適用Cookie,lastModify time请毛,服務(wù)器名稱,版本號(hào),協(xié)議版本號(hào),請(qǐng)求方式GET,POST,請(qǐng)求資源的長(zhǎng)度,常用的就只有accetpt type,Content-Type瞭亮,
@property (readonly, copy) NSURLRequest *request;
//這個(gè)屬性從字面意思都能看得出來,就是緩存request 的響應(yīng)數(shù)據(jù)的,方便下次系統(tǒng)調(diào)用的時(shí)候直接獲取
@property (nullable, readonly, copy) NSCachedURLResponse *cachedResponse;
//這個(gè)屬性用到的比較多,系統(tǒng)在請(qǐng)求網(wǎng)絡(luò)資源或從定向的時(shí)候都會(huì)來詢問這個(gè)方法,如果回答是,則表示 使用用戶自定義的protocol來處理網(wǎng)絡(luò)資源的加載,如果我門需要使用離線加載,則需要將此方法進(jìn)行改寫方仿。
+ (BOOL)canInitWithRequest:(NSURLRequest *)request;
//這個(gè)方法相當(dāng)與事給我門需要進(jìn)行請(qǐng)求的Request對(duì)象的headerFields進(jìn)行重新設(shè)置,我門可以自定一請(qǐng)求頭,這樣我門可以通過request headerFields中的某些特定的屬性來過濾我門不需要處理的Request,讓她們直接采用NSURLLoadingSystem系統(tǒng)的方式進(jìn)行網(wǎng)絡(luò)資源的加載统翩。我門可以通過改寫系統(tǒng)這個(gè)方法,設(shè)置它的通用的請(qǐng)求頭仙蚜, 如 appKey :xxxx, userAgent: xxxx,version: ios Mobile
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request;
//緩存專用API,判斷本地緩存中NSURLRequest對(duì)象和我門需要請(qǐng)求的NSURLRequest對(duì)象是否相同,如果是相通的 厂汗。委粉。。那么娶桦。贾节。。衷畦。
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b;
//開始進(jìn)行資源加載,這個(gè)方法執(zhí)行的前提是當(dāng)我門實(shí)現(xiàn)了
- (void)startLoading;
//停止加載
- (void)stopLoading;
+(BOOL)CanInitWithRequet
方法并返回YES后,并且使用+ (BOOL)registerClass:(Class)protocolClass
注冊(cè)我門自定義的NSURLProtocol子類;才會(huì)執(zhí)行此方法,這就是前面說到的我門自己實(shí)現(xiàn)網(wǎng)絡(luò)資源的加載栗涂。
//下面幾個(gè)APi主要是對(duì)我門需要處理的NSURLRequest對(duì)象進(jìn)行處理,標(biāo)記那些已經(jīng)是請(qǐng)求過的,那些是沒有請(qǐng)求過的祈争。通過KVO的方式給它的headerFIelders添加一個(gè)參數(shù)進(jìn)行判定斤程。
+ (nullable id)propertyForKey:(NSString *)key inRequest:(NSURLRequest *)request;
+ (void)setProperty:(id)value forKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
+ (void)removePropertyForKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
+ (BOOL)registerClass:(Class)protocolClass;
主要是為了配合我門在完成自定義的資源加載過程中的請(qǐng)求,我門只需要在實(shí)現(xiàn)的NSURLSession和NSURLConnection的代理方法中通過鉤子來實(shí)現(xiàn)這些方法就行了,將 URL資源加載成功,加載失敗,加載完成,重定向進(jìn)行重。這樣就保證的在我門自定義處理網(wǎng)絡(luò)資源加載后菩混,最后又將結(jié)果移交給了系統(tǒng)URLLoadingSystem處理忿墅。
NSURLProtocol子類的實(shí)例->URLLoadingSystem-》詢問NSURLProtocol canInitWithRequest-(是)》startLoading->調(diào)用NSURLSession/NSURLConnection進(jìn)行網(wǎng)絡(luò)資源請(qǐng)求-》在請(qǐng)求完成的代理方法中實(shí)現(xiàn)NSURLClientProtocol請(qǐng)求處理。-》注銷NSURLProtocol子類實(shí)例沮峡【纹辏總的來說系統(tǒng)自動(dòng)進(jìn)行URL資源加載->切換手動(dòng)資源加載-》加載結(jié)束切換系統(tǒng)進(jìn)行URL資源加載。而在手動(dòng)進(jìn)行資源加載過程中,這期間的request,response,redirectRequest帖烘,cache亮曹,data橄杨,error,所有的這些時(shí)間都由我門自己定義。 你只需要在子類重寫的canInitWithRequest方法中進(jìn)行攔截我門需要處理的請(qǐng)求進(jìn)行處理就可以了,甚至還可以對(duì)我門項(xiàng)目需要離線加載的頁面做一個(gè)專門的配置文件表照卦,在此方法類的每次請(qǐng)求的URLRequest對(duì)象做一個(gè)判定式矫,然后再進(jìn)行處理。
//下面為NSURLClient的實(shí)現(xiàn)方法,
- (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
```objective-c
//截獲重定向的URL請(qǐng)求頭,確定是否響應(yīng)役耕。
- (void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;
//緩存是否有效
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy;
//設(shè)置Request的緩存策略,由于我門是自定義子類,如果你需要完成自定義的離線緩存采转,那么此方法類需要適用設(shè)置為NSURLCacheStoreagePolicy為NO。
- (void)URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data;
//此方法與NSURLSession didReceiveData 或者NSURLConnection didReceviveData一起使用,將接收到的數(shù)據(jù)返回給NSURLLoadingSystem(系統(tǒng)資源加載系統(tǒng)).這樣才不會(huì)影響我門在其他的類文件里調(diào)用網(wǎng)絡(luò)請(qǐng)求方法獲取數(shù)據(jù)瞬痘。
- (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;
- (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
*自己對(duì)請(qǐng)求的授權(quán)挑戰(zhàn)進(jìn)行處理, 因?yàn)槲议T自定義子類,主要是做離線緩存,或者設(shè)定Request請(qǐng)求頭的一些規(guī)則,以及重定向之類的. 此處你也可以為指定的一些https的請(qǐng)求做一些特殊的處理故慈。
*首先需要拿到challenge的保護(hù)空間,獲取到服務(wù)器的受信任對(duì)象,serverTrust,其實(shí)就是一個(gè)證書憑證,不過現(xiàn)在通過stream流傳輸過來被系統(tǒng)封裝成了一對(duì)象。 如果這個(gè)對(duì)象是
- (void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;