天天看點

ASIHTTPRequest 詳解

ASIHTTPRequest是一款極其強勁的HTTP通路開源項目。讓簡單的API完成複雜的功能,

如:異步請求,隊列請求,GZIP壓縮,緩存,斷點續傳,進度跟蹤,上傳檔案,HTTP認證在新的版本中,還加入了Objective-C閉包Block的支援,讓我們的代碼更加輕簡靈活。

下面就舉例說明它的API用法。

同步意為着線程阻塞,在主線程中使用此方法會使應用Hang住而不響應任何使用者事件。是以,在應用程式設計時,大多被用在專門的子線程增加使用者體驗,或用異步請求代替(下面會講到)。

- (IBAction)grabURL:(id)sender

{

NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];

ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url];

[request startSynchronous];NSError *error = [request error];if (!error) {

NSString *response = [request responseString];}

}

a, 用requestWithURL快捷方法擷取ASIHTTPRequest的一個執行個體

b, startSynchronous 方法啟動同步通路,

c, 由于是同步請求,沒有基于事件的回調方法,是以從request的error屬性擷取錯誤資訊。

d, responseString,為請求的傳回NSString資訊。

異步請求的好處是不阻塞目前線程,但相對于同步請求略為複雜,至少要添加兩個回調方法來擷取異步事件。下面異步請求代碼完成上面同樣的一件事情:

- (IBAction)grabURLInBackground:(id)sender

{

NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];

ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url];

[request setDelegate:self];

[request startAsynchronous];}

  • -  (void)requestFinished:(ASIHTTPRequest *)request{

    // Use when fetching text data

    NSString *responseString = [request responseString];

    // Use when fetching binary data

    NSData *responseData = [request responseData];}

  • -  (void)requestFailed:(ASIHTTPRequest *)request{

    NSError *error = [request error];}

    a,與上面不同的地方是指定了一個 “delegate”,并用startAsynchronous來啟動網絡請求。b,在這裡實作了兩個delegate的方法,當資料請求成功時會調用requestFinished,請求失敗時(如網絡問題或伺服器内部錯誤)會調用requestFailed。

    提供了一個對異步請求更加精準豐富的控制。如,可以設定在隊列中,同步請求的連接配接數。往隊列裡添加的請求執行個體數大于maxConcurrentOperationCount時,請求執行個體将被置為等待,直到前面至少有一個請求完成并出列才被放到隊列裡執行。也适用于當我們有多個請求需求按順序執行的時候(可能是業務上的需要,也可能是軟體上的調優),僅僅需要把maxConcurrentOperationCount設為“1”。

    - (IBAction)grabURLInTheBackground:(id)sender{

    if (![self queue]) {

    [self setQueue:[[[NSOperationQueue alloc] init]

autorelease]];}

NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];

ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url];

[request setDelegate:self];

[request setDidFinishSelector:@selector(requestDone:)];

[request setDidFailSelector:@selector(requestWentWrong:)];

[[self queue] addOperation:request]; //queue is anNSOperationQueue

}

  • -  (void)requestDone:(ASIHTTPRequest *)request{

    NSString *response = [request responseString];}

  • -  (void)requestWentWrong:(ASIHTTPRequest *)request{

    NSError *error = [request error];}

    建立NSOperationQueue,這個Cocoa架構的執行任務(NSOperation)的任務隊列。我們通過ASIHTTPRequest.h的源碼可以看到,此類本身就是一個NSOperation的子類。也就是說它可以直接被放到”任務隊列”中,并被執行。上面的代碼隊了隊列的建立與添加操作外,其它代碼與上一例一樣。a,可以設定一個上下文(userInfo)到request對象中,當請求響應完後可以通過通路request對象的userInfo擷取裡面的資訊b,為每一個請求執行個體設定不同的setDidFinishSelector / setDidFailSelector

的回調方法

c,子類化ASIHTTPRequest,重寫requestFinished: 與 failWithProblem:方法

ASINetworkQueues, delegate提供的更多的回調方法如下:a,requestDidStartSelector,請求發起時會調此方法,你可以在此方法中跟據業務選擇性的設定request對象的deleaget。b,requestDidReceiveResponseHeadersSelector,當接受完響應的Header後設計此方法,這個對下載下傳大資料的時候相當有用,你可以在方法裡做更多業務上的處理。c,requestDidFinishSelector,請求并響應成功完成時調用此方法d,requestDidFailSelector,請求失敗e,queueDidFinishSelector,整個隊列裡的所有請求都結束時調用此方法。

它是NSOperationQueues的擴充,小而強大。但也與它的父類略有差別。如,僅添加到隊列中其實并不能執行請求,隻有調用[ queue g o]才會執行;一個正在運作中的隊列,并不需要重複調用[ queue go ]。預設情況下,隊列中的一個請求如果失敗,它會取消所有未完成的請求。可以設定[ queuesetShouldCancelAllRequestsOnFailure:NO ]來修 正。

首先,同步請求是不能取消的。其次,不管是隊列請求,還是簡單的異步請求,全部調用[ request cancel ]來取消請求。

取消的請求預設都會按請求失敗處理,并調用請求失敗delegate。

如果不想調用delegate方法,則設定:[ request clearDelegatesAndCancel];隊列請求中需要注意的是,如果你取消了一個請求,隊列會自動取消其它所有請求。

如果隻想取消一個請求,可以設定隊列:[ queuesetShouldCancelAllRequestsOnFailure:NO ];

如果想明确取消所有請求:[ queue cancelAllOperations ];

request并沒有retain你的delegate,是以在沒有請求完的時候釋放了此delegate,需要在dealloc方法裡先取消所有請求,再釋放請求執行個體,如:- (void)dealloc

{

[request clearDelegatesAndCancel];[request release];

...

[super dealloc];

}

ASIFormDataRequest ,模拟 Form表單送出,其送出格式與 Header會自動識别。

沒有檔案:application/x-www-form-urlencoded有檔案:multipart/form-data

ASIFormDataRequest *request = [ASIFormDataRequestrequestWithURL:url];

[request setPostValue:@"Ben" forKey:@"first_name"];[request setPostValue:@"Copsey" forKey:@"last_name"];[request setFile:@"/Users/ben/Desktop/ben.jpg"forKey:@"photo"];

[request addData:imageData withFileName:@"george.jpg"andContentType:@"image/jpeg" forKey:@"photos"];如果要發送自定義資料:

ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url];

[request appendPostData:[@"This is my data"dataUsingEncoding:NSUTF8StringEncoding]];

// Default becomes POST when you use appendPostData: /appendPostDataFromFile: / setPostBody:

[request setRequestMethod:@"PUT"];

通過設定request的setDownloadDestinationPath,可以設定下載下傳檔案用的下

載目标目錄。首先,下載下傳過程檔案會儲存在temporaryFileDownloadPath目錄下。如果下載下傳完成會做以下事情:1,如果資料是壓縮的,進行解壓,并把檔案放在downloadDestinationPath目錄中,臨時檔案被删除2,如果下載下傳失敗,臨時檔案被直接移到downloadDestinationPath目錄,并替換同名檔案。

如果你想擷取下載下傳中的所有資料,可以實作delegate中的request:didReceiveData:方法。但如果你實作了這個方法,request在下載下傳完後,request并不把檔案放在downloadDestinationPath中,需要手工處理。

資訊:status , header, responseEncoding

[request responseStatusCode];

[[request responseHeaders] objectForKey:@"X-Powered-By"];

[request responseEncoding];

有兩個回調方法可以擷取請求進度,1,downloadProgressDelegate,可以擷取下載下傳進度2,uploadProgressDelegate,可以擷取上傳進度

cookie如果Cookie存在的話,會把這些資訊放在NSHTTPCookieStorage容器中共享,并供下次使用。

你可以用[ ASIHTTPRequest setSessionCookies:nil ] ; 清空所有Cookies。當然,你也可以取消預設的Cookie政策,而使自定義的Cookie:

//Create a cookie

NSDictionary *properties = [[[NSMutableDictionary alloc]init] autorelease];

[properties setValue:[@"Test Value" encodedCookieValue]forKey:NSHTTPCookieValue];

[properties setValue:@"ASIHTTPRequestTestCookie"forKey:NSHTTPCookieName];

[properties setValue:@".allseeing-i.com"

forKey:NSHTTPCookieDomain];

[properties setValue:[NSDatedateWithTimeIntervalSinceNow:60*60]forKey:NSHTTPCookieExpires];

[properties setValue:@"/asi-http-request/tests"forKey:NSHTTPCookiePath];

NSHTTPCookie *cookie = [[[NSHTTPCookie alloc]initWithProperties:properties] autorelease];

//This url will return the value of the'ASIHTTPRequestTestCookie' cookie

url = [NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/read_cookie"];

request = [ASIHTTPRequest requestWithURL:url];[request setUseCookiePersistence:NO];

[request setRequestCookies:[NSMutableArrayarrayWithObject:cookie]];

[request startSynchronous];

//Should be: I have 'Test Value' as the value of'ASIHTTPRequestTestCookie'

NSLog(@"%@",[request responseString]);

0.94以後支援大檔案的斷點下載下傳,隻需要設定:

[ request setAllowResumeForFileDownloads:YES ];

[ request setDownloadDestinationPath:downloadPath ];

就可以了。ASIHTTPRequest會自動儲存通路過的URL資訊,并備之後用。在以下幾個場景非常有用:

1,當沒有網絡連接配接的時候。2,已下載下傳的資料再次請求時,僅當它與本地版本不樣時才進行下載下傳。ASIDownloadCache 它對Get請求的響應資料進行緩存(被緩存的資料必需是成功的200請求):

[ASIHTTPRequest setDefaultCache:[ASIDownloadCachesharedCache]];當設定緩存政策後,所有的請求都被自動的緩存起來。另外,如果僅僅希望某次請求使用緩存操作,也可以這樣使用:ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url];

[request setDownloadCache:[ASIDownloadCachesharedCache]];

僅僅需要建立不同的ASIDownloadCache,并設定緩存所使用的路徑,并設定到需要使用的request執行個體中:

ASIDownloadCache *cache = [[[ASIDownloadCache alloc]init] autorelease];

[cache setStoragePath:@"/Users/ben/Documents/Cached-Downloads"];

[self setMyCache:cache];

ASIHTTPRequest *request = [ASIHTTPRequestrequestWithURL:url];

[request setDownloadCache:[self myCache]];

緩存政策是我們控制緩存行為的主要方式,如:什麼時候進行緩存,緩存資料的利用方式。

以下是政策可選清單(可組合使用):

ASIUseDefaultCachePolicy

ASIDoNotReadFromCacheCachePolicy

這是一個預設的緩存政策“ASIAskServerIfModifiedWhenStaleCachePolicy”,這個很明白,見名知意(它不能與其它政策組合使用)

所讀資料不使用緩存ASIDoNotWriteToCacheCachePolicy 不對緩存資料進行寫操作

預設緩存行為,request會先判斷是否存在緩存資料。a, 如果沒有再進行網絡請求。b,如果存在緩存資料,并且資料沒有過

ASIAskServerIfModifiedWhenStaleC 期,則使用緩存。c,如果存在緩存資料,achePolicy 但已經過期,request會先進行網絡請求,

判斷伺服器版本與本地版本是否一樣,如果 一樣,則使用緩存。如果伺服器有新版本,

能與其它政策組合使用)

ASIDoNotReadFromCacheCachePolicy

所讀資料不使用緩存ASIDoNotWriteToCacheCachePolicy 不對緩存資料進行寫操作

ASIAskServerIfModifiedWhenStaleCachePolicy

ASIAskServerIfModifiedCachePolicyASIOnlyLoadIfNotCachedCachePolicy

ASIDontLoadCachePolicy

ASIFallbackToCacheIfLoadFailsCachePolicy

預設緩存行為,request會先判斷是否存在緩存資料。a, 如果沒有再進行網絡請求。b,如果存在緩存資料,并且資料沒有過期,則使用緩存。c,如果存在緩存資料,但已經過期,request會先進行網絡請求,判斷伺服器版本與本地版本是否一樣,如果一樣,則使用緩存。如果伺服器有新版本,會進行網絡請求,并更新本地緩存與預設緩存大緻一樣,差別僅是每次請求都會 去伺服器判斷是否有更新

如果有緩存在本地,不管其過期與否,總會

拿來使用

僅當有緩存的時候才會被正确執行,如果沒有緩存,request将被取消(沒有錯誤資訊)這個選項經常被用來與其它選項組合使用。請求失敗時,如果有緩存當網絡則傳回本地緩存資訊(這個在處理異常時非常有用)

如果設定了“defaultCachePolicy”則所有的請求都會使用此緩存。

你可以設定緩存的資料需要儲存多長時間,ASIHTTPRequest提供了兩種政策:a,ASICacheForSessionDurationCacheStoragePolicy,預設政策,基于session的緩存資料存儲。當下次運作或[ASIHTTPRequest clearSession]時,緩存将失效。b,ASICachePermanentlyCacheStoragePolicy,把緩存資料永久儲存在本地,

如:

ASIHTTPRequest *request = [ ASIHTTPRequestrequestWithURL:url ];

[ request

setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy ];另外,也可以使用clearCachedResponsesForStoragePolicy來清空指定政策下的緩存資料。

設定是否按伺服器在Header裡指定的是否可被緩存或過期政策進行緩存:[[ ASIDownloadCache sharedCache ]setShouldRespectCacheControlHeaders:NO ];設定request緩存的有效時間:

[ request setSecondsToCache:60*60*24*30 ]; // 緩存30天可以判斷資料是否從緩存讀取:

[ request didUseCachedResponse ];

設定緩存所使用的路徑:

[ request setDownloadDestinationPath:[[ ASIDownloadCachesharedCache ]pathToStoreCachedResponseDataForRequest:request ]];隻要簡單的實作ASICacheDelegate接口就可以被用來使用。

預設的情況下,ASIHTTPRequest會使用被設定的預設代理。但你也可以手動修改http代理:

// Configure a proxy server manually

NSURL *url = [ NSURL URLWithString:@"http://allseeing-i.com/ignore" ];

ASIHTTPRequest *request = [ ASIHTTPRequestrequestWithURL:url ];

[ request setProxyHost:@"192.168.0.1" ];[ request setProxyPort:3128 ];

// Alternatively, you can use a manually-specified ProxyAuto Config file (PAC)

// (It's probably best if you use a local file)[request setPACurl:[NSURL URLWithString:@"file:///Users/

ben/Desktop/test.pac"]];

ASIHTTPRequest,iOS4中,當應用背景運作時仍然請求資料:

[ requestsetShouldContinueWhenAppEntersBackground:YES ];是否有網絡請求:

[ ASIHTTPRequest isNetworkInUse ]是否顯示網絡請求資訊在status bar上:

[ ASIHTTPRequestsetShouldUpdateNetworkActivityIndicator:NO ];設定請求逾時時,設定重試的次數:

[ request setNumberOfTimesToRetryOnTimeout:2 ];KeepAlive的支援:

// Set the amount of time to hang on to a persistentconnection before it should expire to 2 minutes

[ request setPersistentConnectionTimeoutSeconds:120 ];

// Disable persistent connections entirely

[ request setShouldAttemptPersistentConnection:NO ];... other posts by pimacun

每次在工程中添加ASIHttpRequest都記不住要加哪些庫,還是别懶了,好記性不如爛筆頭,寫下來吧。

libz.dylib

SystemConfiguration.framework

CFNetwork.framework

MobileCoreServices.framework

這四個應該就夠了,添加之後,項目可以編譯通過。

SDWebImage需要用到的framework

使用目前GitHub上最新的2.6版本,需要添加

MapKit.framework

ImageIO.framework