第三方蘋果開發庫之ASIHTTPRequest(翻譯版)


來自:http://www.dreamingwish.com/dream-2011/apples-third-party-development-libraries-asihttprequest.html

第三方蘋果開發庫之ASIHTTPRequest

 

  1. ASIHttpRequest庫簡介、配置和安裝
  2. ASIHttpRequest-創建和執行request
  3. ASIHttpRequest-發送數據
  4. ASIHTTPRequest-下載數據
  5. ASIHTTPRequest-進度追蹤
  6. ASIHTTPRequest-身份驗證
  7. ASIHTTPRequest-HTTP授權-流程圖
  8. ASIHTTPRequest-Cookie的使用
  9. ASIHTTPRequest-數據壓縮
  10. ASIHTTPRequest-斷點續傳(下載)
  11. ASIHTTPRequest-直接讀取磁盤數據流的請求體
  12. ASIHTTPRequest-使用download cache
  13. ASIHTTPRequest-流量控制
  14. ASIHTTPRequest-客戶端證書支持
  15. ASIHTTPRequest-使用代理連接
  16. ASIHTTPRequest-其他特性
  17. ASIHTTPRequest-Debug選項

相關網絡資料:

  1. 升級到iOS5后ASIHttpRequest庫問題及解決方法 解決iOS5網絡代理彈出框問題(備用地址:http://www.cocoachina.com/iphonedev/sdk/2011/1021/3403.html)

 

ASIHttpRequest庫簡介、配置和安裝

發布者: Seven's - 2011/10/12 - 分類:ASIHTTPRequest中文文檔

 

使用ASIHTTPRequest可以很方便的進行一下操作:

  • 同步/異步方式下載數據
  • 定義下載隊列,讓隊列中的任務按指定的並發數來下載(隊列下載必須是異步的)
  • 提交表單,文件上傳
  • 處理cookie
  • 設置代理
  • 上下載進度條
  • 重定向處理
  • 請求與響應的GZIP
  • 驗證與授權

等等,只要跟HTTP有關,只有你想不到的,沒有她做不到的~

配置方法:

  • ASIHTTPRequestConfig.h
  • ASIHTTPRequestDelegate.h
  • ASIProgressDelegate.h
  • ASICacheDelegate.h
  • ASIHTTPRequest.h
  • ASIHTTPRequest.m
  • ASIDataCompressor.h
  • ASIDataCompressor.m
  • ASIDataDecompressor.h
  • ASIDataDecompressor.m
  • ASIFormDataRequest.h
  • ASIInputStream.h
  • ASIInputStream.m
  • ASIFormDataRequest.m
  • ASINetworkQueue.h
  • ASINetworkQueue.m
  • ASIDownloadCache.h
  • ASIDownloadCache.m

iPhone 工程還需要:

  • ASIAuthenticationDialog.h
  • ASIAuthenticationDialog.m
  • Reachability.h (在External/Reachability 目錄下)
  • Reachability.m (在 External/Reachability 目錄下)

庫引用:

CFNetwork.framework

SystemConfiguration.framework

MobileCoreServices.framework

CoreGraphics.framework

和libz.dylib

另外,還需要libxml2.dylib(libxml2還需要設置連接選項-lxml2 和頭文件搜索路徑/usr/include/libxml2)

 

ASIHttpRequest-創建和執行request

發布者: Seven's - 2011/10/12 - 分類:ASIHTTPRequest中文文檔

 

同步請求

同步請求會在當前線程中執行,使用error屬性來檢查結束狀態(要下載大文件,則需要設定downloadDestinationPath來保存文件到本地):

- (IBAction)grabURL:(id)sender
{
  NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];
  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  [request startSynchronous];
  NSError *error = [request error];
  if (!error) {
    NSString *response = [request responseString];
  }
}

同步請求會阻塞主線程的執行,這導致用戶界面不響應用戶操作,任何動畫都會停止渲染。

 

異步請求

下面是最簡單的異步請求方法,這個request會在全局的NSOperationQueue中執行,若要進行更復雜的操作,我們需要自己創建NSOperationQueue或者ASINetworkQueue,后面會講到。

- (IBAction)grabURLInBackground:(id)sender
{
   NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];
   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL: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];
}

 

使用block

在平台支持情況下,ASIHTTPRequest1.8以上支持block。

- (IBAction)grabURLInBackground:(id)sender
{
   NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
   __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
   [request setCompletionBlock:^{
      // Use when fetching text data
      NSString *responseString = [request responseString];

      // Use when fetching binary data
      NSData *responseData = [request responseData];
   }];
   [request setFailedBlock:^{
      NSError *error = [request error];
   }];
   [request startAsynchronous];
}

注意,聲明request時要使用__block修飾符,這是為了告訴block不要retain request,以免出現retain循環,因為request是會retain block的。

 

使用隊列

創建NSOperationQueue或者ASINetworkQueue隊列,我們還可以設定最大並發連接數:maxConcurrentOperationCount 

- (IBAction)grabURLInTheBackground:(id)sender
{
   if (![self queue]) {
      [self setQueue:[[[NSOperationQueue alloc] init] autorelease]];
      [self queue].maxConcurrentOperationCount = 4;
   }

   NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];
   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
   [request setDelegate:self];
   [request setDidFinishSelector:@selector(requestDone:)];
   [request setDidFailSelector:@selector(requestWentWrong:)];
   [[self queue] addOperation:request]; //queue is an NSOperationQueue
}

- (void)requestDone:(ASIHTTPRequest *)request
{
   NSString *response = [request responseString];
}

- (void)requestWentWrong:(ASIHTTPRequest *)request
{
   NSError *error = [request error];
}

如果不設定selector,那么系統會使用默認的requestFinished: 和 requestFailed:方法

如果需要對隊列里面的每個request進行區分,那么可以設定request的userInfo屬性,它是個NSDictionary,或者更簡單的方法是設定每個request的tag屬性,這兩個屬性都不會被發送到服務器。

不要使用request的URL來區分每個request,因為URL可能會改變(例如重定向),如果需要使用request的URL,使用[request originalURL],這個將永遠返回第一個url。

對於ASINetworkQueue

ASINetworkQueue是NSOperationQueue的子類,提供更高級的特性(ASINetworkQueue的代理函數):

  • requestDidStartSelector
    當一個request開始執行時,這個代理函數會被調用。
  • requestDidReceiveResponseHeadersSelector
    當隊列中的request收到服務器返回的頭信息時,這個代理函數會被調用。對於下載很大的文件,這個通常比整個request的完成要早。
  • requestDidFinishSelector
    當每個request完成時,這個代理函數會被調用。
  • requestDidFailSelector
    當每個request失敗時,這個代理函數會被調用。
  • queueDidFinishSelector
    當隊列完成(無論request失敗還是成功)時,這個代理函數會被調用。

ASINetworkQueues與NSOperationQueues稍有不同,加入隊列的request不會立即開始執行。如果隊列打開了進度開關,那么隊列開始時,會先對所有GET型request進行一次HEAD請求,獲得總下載大小,然后真正的request才被執行。

向一個已經開始進行的ASINetworkQueue 加入request會怎樣?

如果你使用ASINetworkQueue來跟蹤若干request的進度,只有當新的request開始執行時,總進度才會進行自適應調整(向后移動)。ASINetworkQueue不會為隊列開始后才加入的request進行HEAD請求,所以如果你一次向一個正在執行的隊列加入很多request,那么總進度不會立即被更新。

如果隊列已經開始了,不需要再次調用[queue go]。

當ASINetworkQueue中的一個request失敗時,默認情況下,ASINetworkQueue會取消所有其他的request。要禁用這個特性,設置 [queue setShouldCancelAllRequestsOnFailure:NO]

ASINetworkQueues只可以執行ASIHTTPRequest操作,二不可以用於通用操作。試圖加入一個不是ASIHTTPRequest的NSOperation將會導致拋出錯誤。

 

取消異步請求

取消一個異步請求(無論request是由[request startAsynchronous]開始的還是從你創建的隊列中開始的),使用[request cancel]即可。注意同步請求不可以被取消。

注意,如果你取消了一個request,那么這個request將會被視為請求失敗,並且request的代理或者隊列的代理的失敗代理函數將被調用。如果你不想讓代理函數被調用,那么將delegate設置為nil,或者使用clearDelegatesAndCancel方法來取消request。

clearDelegatesAndCancel 將會首先清除所有的代理和block。

當使用ASINetworkQueue時,如果取消了隊列中的一個request,那么隊列中其他所有request都會被取消,可以設置shouldCancelAllRequestsOnFailure的值為NO來避免這個現象。

 

安全地控制delegate防止request完成之前代理被釋放

request並不retain它們的代理,所以有可能你已經釋放了代理,而之后request完成了,這將會引起崩潰。大多數情況下,如果你的代理即將被釋放,你一定也希望取消所有request,因為你已經不再關心它們的返回情況了。如此做:

// 代理類的dealloc函數
- (void)dealloc
{
   [request clearDelegatesAndCancel];
   [request release];
   ...
   [super dealloc];
}


ASIHttpRequest-發送數據

 

 

發送數據

設定request頭

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request addRequestHeader:@"Referer" value:@"http://www.dreamingwish.com/"];

使用ASIFormDataRequest POST表單

通常數據是以’application/x-www-form-urlencoded’格式發送的,如果上傳了二進制數據或者文件,那么格式將自動變為‘multipart/form-data’ 

文件中的數據是需要時才從磁盤加載,所以只要web server能處理,那么上傳大文件是沒有問題的。

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

數據的mime頭是自動判定的,但是如果你想自定義mime頭,那么這樣:

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];

// Upload a file on disk
[request setFile:@"/Users/ben/Desktop/ben.jpg" withFileName:@"myphoto.jpg" andContentType:@"image/jpeg"
forKey:@"photo"];

// Upload an NSData instance
[request setData:imageData withFileName:@"myphoto.jpg" andContentType:@"image/jpeg" forKey:@"photo"];

你可以使用addPostValue方法來發送相同name的多個數據(夢維:服務端會以數組方式呈現):

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request addPostValue:@"Ben" forKey:@"names"];
[request addPostValue:@"George" forKey:@"names"];
[request addFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photos"];
[request addData:imageData withFileName:@"george.jpg" andContentType:@"image/jpeg" forKey:@"photos"];

PUT請求、自定義POST請求

如果你想發送PUT請求,或者你想自定義POST請求,使用appendPostData: 或者 appendPostDataFromFile:

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request appendPostData:[@"This is my data" dataUsingEncoding:NSUTF8StringEncoding]];
// Default becomes POST when you use appendPostData: / appendPostDataFromFile: / setPostBody:
[request setRequestMethod:@"PUT"];
 
            

ASIHTTPRequest-下載數據

 
            

將服務器響應數據直接下載到文件

如果你請求的資源很大,你可以直接將數據下載到文件中來節省內存。此時,ASIHTTPRequest將不會一次將返回數據全部保持在內存中。

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadDestinationPath:@"/Users/ben/Desktop/my_file.txt"];

當我們把數據下載到downloadDestinationPath時,數據將首先被存在臨時文件中。此時文件的路徑名存儲在temporaryFileDownloadPath中(夢維:如果不設置這個值,會自動生成一個文件名,在模擬器中,文件被創建在$TMPDIR中)。當request完成時,會發生下面兩件事之一:

  • 如果數據是被壓縮過(gzip)的,那么這個壓縮過的文件將被解壓到downloadDestinationPath,臨時文件會被刪除。
  • 如果數據未被壓縮,那么這個文件將被移動到downloadDestinationPath,沖突解決方式是:覆蓋已存在的文件。

注意,如果服務器響應數據為空,那么文件是不會被創建的。如果你的返回數據可能為空,那么你應該先檢查下載文件是否存在,再對文件進行操作。

 

處理收到的服務器響應數據

如果你想處理服務器響應的數據(例如,你想使用流解析器對正在下載的數據流進行處理),你應該實現代理函數 request:didReceiveData:。注意如果你這么做了,ASIHTTPRequest將不會填充responseData到內存,也不會將數據寫入文件(downloadDestinationPath )——你必須自己搞定這兩件事(之一)。 

 

獲取HTTP狀態碼

ASIHTTPRequest並不對HTTP狀態碼做任何處理(除了重定向和授權狀態碼,下面會介紹到),所以你必須自己檢查狀態值並正確處理。

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
int statusCode = [request responseStatusCode];
NSString *statusMessage = [request responseStatusMessage];

 

讀取響應頭

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSString *poweredBy = [[request responseHeaders] objectForKey:@"X-Powered-By"];
NSString *contentType = [[request responseHeaders] objectForKey:@"Content-Type"];

 

處理文本編碼

ASIHTTPRequest會試圖讀取返回數據的編碼信息(Content-Type頭信息)。如果它發現了編碼信息,它會將編碼信息設定為合適的 NSStringEncoding.如果它沒有找到編碼信息,它會將編碼設定為默認編碼(NSISOLatin1StringEncoding)。

當你調用[request responseString],ASIHTTPRequest會嘗試以responseEncoding將返回的Data轉換為NSString。

 

處理重定向

當遇到以下HTTP狀態碼之一時,ASIHTTPRequest會自動重定向到新的URL:

  • 301 Moved Permanently
  • 302 Found
  • 303 See Other

當發生重定向時,響應數據的值(responseHeaders,responseCookies,responseData,responseString等等)將會映射為最終地址的相應返回數據。

當URL發生循環重定向時,設置在這個URL上的cookie將被儲存到全局域中,並在適當的時候隨重定向的請求發送到服務器。

Cookies set on any of the urls encountered during a redirection cycle will be stored in the global cookie store, and will be represented to the server on the redirected request when appropriate.

你可以關閉自動重定向:將shouldRedirect設置為NO。

默認情況下,自動重定向會使用GET請求(請求體為空)。這種行為符合大多數瀏覽器的行為,但是HTTP spec規定301和302重定向必須使用原有方法。

要對301、302重定向使用原方法(包含請求體),在發起請求之前,設置shouldUseRFC2616RedirectBehaviour 為YES。

 

ASIHTTPRequest-進度追蹤

 
            
 

每個ASIHTTPRequest有兩個delegate用來追蹤進度:

  • downloadProgressDelegate 下載)
  • uploadProgressDelegate (上載).

進度delegate可以是NSProgressIndicators (Mac OS X) 或者 UIProgressViews (iPhone).ASIHTTPRequest會自適應這兩個class的行為。你也可以使用自定義class作為進度delegate,只要它響應setProgress:函數。

  • 如果你執行單個request,那么你需要為該request設定upload/download進度delegate
  • 如果你在進行多個請求,並且你想要追蹤整個隊列中的進度,你必須使用ASINetworkQueue並設置隊列的進度delegate
  • 如果上述兩者你想同時擁有,恭喜你,0.97版以后的ASIHTTPRequest,這個可以有 ^ ^

IMPORTANT:如果你向一個要求身份驗證的網站上傳數據,那么每次授權失敗,上傳進度條就會被重置為上一次的進度值。因此,當與需要授權的web服務器交互時,建議僅當useSessionPersistence為YES時才使用上傳進度條,並且確保你在追蹤大量數據的上傳進度之前,先使用另外的request來進行授權。 

追蹤小於128KB的數據上傳進度目前無法做到,而對於大於128kb的數據,進度delegate不會收到第一個128kb數據塊的進度信息。這是因為CFNetwork庫API的限制。我們曾向apple提交過bug報告(bug id 6596016),希望apple能修改CFNetwork庫以便實現上述功能。

2009-6-21:Apple的哥們兒們真棒!iPhone 3.0 SDK里,buffer大小已經被減小到32KB了,我們的上傳進度條可以更精確了。

 

追蹤單個request的下載進度

這個例子中, myProgressIndicator是個 NSProgressIndicator.

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadProgressDelegate:myProgressIndicator];
[request startSynchronous];
NSLog(@"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);

 

追蹤一系列request的下載進度

在這個例子中, myProgressIndicator 是個 UIProgressView, myQueue是個 ASINetworkQueue.

- (void)fetchThisURLFiveTimes:(NSURL *)url
{
   [myQueue cancelAllOperations];
   [myQueue setDownloadProgressDelegate:myProgressIndicator];
   [myQueue setDelegate:self];
   [myQueue setRequestDidFinishSelector:@selector(queueComplete:)];
   int i;
   for (i=0; i<5; i++) {
      ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
      [myQueue addOperation:request];
   }
   [myQueue go];
}
 
- (void)queueComplete:(ASINetworkQueue *)queue
{
   NSLog(@"Value: %f", [myProgressIndicator progress]);
}

這個例子中,我們已經為ASINetworkQueues調用過[myQueue go]了。

 

追蹤單個request的上傳進度

在這個例子中, myProgressIndicator 是個 UIProgressView。

ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:@"Ben" forKey:@"first_name"];
[request setPostValue:@"Copsey" forKey:@"last_name"];
[request setUploadProgressDelegate:myProgressIndicator];
[request startSynchronous];
NSLog(@"Value: %f",[myProgressIndicator progress]);

 

追蹤一系列request的上傳進度

這個例子中, myProgressIndicator是個 NSProgressIndicator, myQueue是個ASINetworkQueue.

- (void)uploadSomethingFiveTimes:(NSURL *)url
{
   [myQueue cancelAllOperations];
   [myQueue setUploadProgressDelegate:myProgressIndicator];
   [myQueue setDelegate:self];
   [myQueue setRequestDidFinishSelector:@selector(queueComplete:)];
   int i;
   for (i=0; i<5; i++) {
      ASIHTTPRequest *request = [ASIFormDataRequest requestWithURL:url];
      [request setPostBody:[@"Some data" dataUsingEncoding:NSUTF8StringEncoding]];
      [myQueue addOperation:request];
   }
   [myQueue go];
}
 
- (void)queueComplete:(ASINetworkQueue *)queue
{
   NSLog(@"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);
}

 

精確進度條vs簡單進度條

ASIHTTPRequest提供兩種進度條顯示,簡單進度條和精確進度條,使用ASIHTTPRequests 和ASINetworkQueues的showAccurateProgress 來控制。為一個request設置showAccurateProgress只會對該request有效。如果你為一個隊列設置showAccurateProgress,那么會影響隊列里所有的request。

簡單進度條

當使用簡單進度條時,進度條只會在一個request完成時才更新。對於單個request,這意味着你只有兩個進度狀態:0%和100%。對於一個有5個request的隊列來說,有五個狀態:0%,25%,50%,75%,100%,每個request完成時,進度條增長一次。

簡單進度條(showAccurateProgress = NO)是ASINetworkQueue的默認值,適用於大量小數據請求。

精確進度條

當使用精確進度條時,每當字節被上傳或下載時,進度條都會更新。它適用於上傳/下載大塊數據的請求,並且會更好的顯示已經發送/接收的數據量。

使用精確進度條追蹤上傳會輕微降低界面效率,因為進度delegate(一般是UIProgressViews 或NSProgressIndicators)會更頻繁地重繪。

使用精確進度條追蹤下載會更影響界面效率,因為隊列會先為每個GET型request進行HEAD請求,以便統計總下載量。強烈推薦對下載大文件的隊列使用精確進度條,但是要避免對大量小數據請求使用精確進度條。

精確進度條(showAccurateProgress = YES)是以同步方式執行的ASIHTTPRequest的默認值。

 

自定義進度追蹤

ASIProgressDelegate 協議定義了所有能更新一個request進度的方法。多數情況下,設置你的uploadProgressDelegate或者 downloadProgressDelegate為 NSProgressIndicator或者UIProgressView會很好。但是,如果你想進行更復雜的追蹤,你的進度delegate實現下列函數要比 setProgress: (iOS) 或者 setDoubleValue: / setMaxValue: (Mac)好:

這些函數允許你在實際量的數據被上傳或下載時更新進度,而非簡單方法的0到1之間的數字。

downloadProgressDelegates方法

  • request:didReceiveBytes: 每次request下載了更多數據時,這個函數會被調用(注意,這個函數與一般的代理實現的 request:didReceiveData:函數不同)。
  • request:incrementDownloadSizeBy: 當下載的大小發生改變時,這個函數會被調用,傳入的參數是你需要增加的大小。這通常發生在request收到響應頭並且找到下載大小時。

uploadProgressDelegates方法

  • request:didSendBytes: 每次request可以發送更多數據時,這個函數會被調用。注意:當一個request需要消除上傳進度時(通常是該request發送了一段數據,但是因為授權失敗或者其他什么原因導致這段數據需要重發)這個函數會被傳入一個小於零的數字。

ASIHTTPRequest-身份驗證

 

你可以查閱ASIHTTPRequest授權流程圖來了解ASIHTTPRequest如何找到授權憑據,並將授權憑據應用到request上。

為URL指定要使用的用戶名和密碼

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

為request指定要使用的用戶名和密碼

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUsername:@"username"];
[request setPassword:@"password"];

將憑據存儲到keychain

如果打開了keychainPersistence,所有提供的可用的用戶名和密碼將被存儲到keychain中,以后的request將會重用這些用戶名密碼,即使你關閉程序后重新打開也不影響。

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUseKeychainPersistence:YES];
[request setUsername:@"username"];
[request setPassword:@"password"];

如果你使用keychain但是想要自己管理它,你可以在ASIHTTPRequest.h文件里找到相關的類方法。

將憑據存儲到session中

如果打開了useSessionPersistence(默認即是如此),ASIHTTPRequest會把憑據存儲到內存中,后來的request將會重用這些憑據。

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUsername:@"username"];
[request setPassword:@"password"];
[request setUseSessionPersistence:YES]; //這一項是默認的,所以並不必要

//將會重用我們的 username 和 password
request = [ASIHTTPRequest requestWithURL:url];

NTLM授權

要使用NTLM授權的Windows服務器,你還需要指定你要進行授權域。

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUsername:@"username"];
[request setPassword:@"password"];
[request setDomain:@"my-domain"];

使用代理來提供憑據

你不一定非要提前指定授權憑據,你還可以讓每個request在無法從session或keychain中找到憑據時向它們的代理請求憑據。如果你要連接到一個你並不清楚授權類型的服務器時,這是很有用的。

你的delegate必須實現authenticationNeededForRequest:方法,當request等待憑據時,ASIHTTPRequest將會暫停這個request。如果你持有你需要的憑據,那么先為request設定憑據,然后調用[request retryUsingSuppliedCredentials]即可。如果你想取消授權,調用[request cancelAuthentication],此時,這個request也會被取消。

從1.0.8版開始,一次只能有一個request的delegate收到authenticationNeededForRequest: 或者 proxyAuthenticationNeededForRequest:。當delegate處理第一個request時,其他需要授權的request將會被暫停。如果提供了一個憑據,當前進程中所有其他的request將會假定這個憑據對這個URL有效,並嘗試重用這個憑據。如果delegate取消了授權,並且隊列的shouldCancelAllRequestsOnFailure值為YES,所有其他的request都將被取消(它們也不會嘗試請求憑據)。

當進行同步請求時,你不可以使用代理模式來授權。

在較老的版本中,這么做會導致程序假死,從1.0.8開始,即使你這么做了,代理函數也不會被調用。

使用內建的授權對話框(目前只對iOS有效)

 

這個特性歸功於1.0.8版本的新類ASIAuthenticationDialog 。這個特性主要是用於授權代理(后面會介紹到),但是它也可以用來向用戶取得授權憑據。

為了更好的用戶體驗,大多數(連接單一服務的)app必須為request的delegate實現authenticationNeededForRequest:方法,或者避免同時使用代理式授權。

most apps that connect to a single service should implement authenticationNeededForRequest: in their request delegates, or avoid the use of delegation-style authentication altogether.

但是,會有一些情況下,為普通的授權使用ASIHTTPRequest的標准授權對話框更好:

  • 你不想創建你自己的登錄表單
  • 你可能需要從外部資源獲取數據,但是你不清楚你需不需要進行授權

對於這些情況,為request設置shouldPresentAuthenticationDialog為YES,此時,如果你的代理沒有實現

asihttprequest授權對話框

authenticationNeededForRequest:方法,那么用戶將會看到這個對話框。

一次同時只有一個對話框可以顯示出來,所以當一個對話框顯示時,所有其他需要授權的request將會暫停。如果提供了一個憑據,當前進程中所有其他的request將會假定這個憑據對這個URL有效,並嘗試重用這個憑據。如果delegate取消了授權,並且隊列的shouldCancelAllRequestsOnFailure值為YES,所有其他的request都將被取消(它們也不會嘗試請求憑據)。

對於同步請求的request,授權對話框不會顯示出來。

這個對話框部分模仿了iPhone上Safari使用的授權對話框,它包含以下內容:

  • 一段信息來說明這些憑據是用於websever(而非一個proxy)
  • 你將要連接到服務器的主機名或者IP
  • 授權域(如果提供的話)
  • 填寫用戶名和密碼的區域
  • 當連接到NTLM授權模式的服務器時,還會包含一個填寫domain的區域
  • 一個說明信息,指明憑據是否將會被以明文方式發送(例如:“只有當使用基於非SSL的基本授權模式時才會以明文方式發送”)

如果你想改變它的外觀,你必須繼承ASIHTTPRequest,並重寫showAuthenticationDialog來顯示你自己的對話框或ASIAuthenticationDialog子類。

在服務器請求憑據前向服務器發送憑據

IMPORTANT

從1.8.1開始,使用基本授權模式的request時,這個特性的行為改變了。你可能需要修改你的代碼。

在第一次生成request時,ASIHTTPRequest可以先向服務器發送憑據(如果有的話),而不是等服務器要求提供憑據時才提供憑據。這個特性可以提高使用授權的程序的執行效率,因為這個特性避免了多余的request。

對於基本授權模式,要觸發這個行為,你必須手動設置request的authenticationScheme為kCFHTTPAuthenticationSchemeBasic:

[request setAuthenticationScheme:(NSString *)kCFHTTPAuthenticationSchemeBasic];

對於其他授權方案,憑據也可以在服務器要求之前被發送,但是僅當有另一個request成功授權之后才行。

在以下情況下,你也許想要禁用這個特性:

  • 你的程序可能會一次使用一系列憑據來與服務器對話
  • 安全性對於你的程序來說非常重要。使用這個特性是相對不安全的,因為你不能在憑據被發送前驗證你是否連接到了正確的服務器。

要禁用這個特性,這樣做:

[request setShouldPresentCredentialsBeforeChallenge:NO];

 

 

ASIHTTPRequest-HTTP授權-流程圖

 





























































 
            

ASIHTTPRequest-Cookie的使用

 

持久化cookie

ASIHTTPRequest允許你使用全局存儲來和所有使用CFNetwork或者NSURLRequest接口的程序共享cookie。

如果設置useCookiePersistence為YES(默認值),cookie會被存儲在共享的 NSHTTPCookieStorage 容器中,並且會自動被其他request重用。值得一提的是,ASIHTTPRequest會向服務器發送其他程序創建的cookie(如果這些cookie對特定request有效的話)。

你可以清空session期間創建的所有cookie:

[ASIHTTPRequest setSessionCookies:nil];

這里的‘session cookies’指的是一個session中創建的所有cookie,而非沒有過期時間的cookie(即通常所指的會話cookie,這種cookie會在程序結束時被清除)。

另外,有個方便的函數 clearSession可以清除session期間產生的所有的cookie和緩存的授權數據。 

 

自己處理cookie

如果你願意,你大可以關閉useCookiePersistence,自己來管理某個request的一系列cookie:

//創建一個cookie
NSDictionary *properties = [[[NSMutableDictionary alloc] init] autorelease];
[properties setValue:[@"Test Value" encodedCookieValue] forKey:NSHTTPCookieValue];
[properties setValue:@"ASIHTTPRequestTestCookie" forKey:NSHTTPCookieName];
[properties setValue:@".dreamingwish.com" forKey:NSHTTPCookieDomain];
[properties setValue:[NSDate dateWithTimeIntervalSinceNow:60*60] forKey:NSHTTPCookieExpires];
[properties setValue:@"/asi-http-request/tests" forKey:NSHTTPCookiePath];
NSHTTPCookie *cookie = [[[NSHTTPCookie alloc] initWithProperties:properties] autorelease];

//這個url會返回名為'ASIHTTPRequestTestCookie'的cookie的值
url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
request = [ASIHTTPRequest requestWithURL:url];
[request setUseCookiePersistence:NO];
[request setRequestCookies:[NSMutableArray arrayWithObject:cookie]];
[request startSynchronous];

//將會打印: I have 'Test Value' as the value of 'ASIHTTPRequestTestCookie'
NSLog(@"%@",[request responseString]);
 
            

ASIHTTPRequest-數據壓縮

 

使用gzip來處理壓縮的響應數據

從0.9版本開始,ASIHTTPRequest會提示服務器它可以接收gzip壓縮過的數據。

許多web服務器可以在數據被發送之前壓縮這些數據——這可以加快下載速度減少流量使用,但會讓服務器的cpu(壓縮數據)和客戶端(解壓數據)付出代價。總的來說,只有特定的幾種數據會被壓縮——許多二進制格式的文件像jpeg,gif,png,swf和pdf已經壓縮過他們的數據了,所以向客戶端發送這些數據時不會進行gzip壓縮。文本文件例如網頁和xml文件會被壓縮,因為它們通常有大量的數據冗余。

 

怎樣設置apache的mod_deflate來使用gzip壓縮數據

apache 2.x以上版本已經配備了mod_deflate擴展,這使得apache可以透明地壓縮特定種類的數據。要開啟這個特性,你需要在apache的配置文件中啟用mod_deflate。並將mod_deflate命令添加到你的虛擬主機配置或者.htaccess文件中。

 

在ASIHTTPRequest中使用gzip

- (IBAction)grabURL:(id)sender
{
  NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];
  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  // 默認為YES, 你可以設定它為NO來禁用gzip壓縮
  [request setAllowCompressedResponse:YES];
  [request startSynchronous];
  BOOL *dataWasCompressed = [request isResponseCompressed]; // 響應是否被gzip壓縮過?
  NSData *compressedResponse = [request rawResponseData]; // 壓縮的數據
  NSData *uncompressedData = [request responseData]; // 解壓縮后的數據
  NSString *response = [request responseString]; // 解壓縮后的字符串
}

當allowCompressedResponse 設置為YES時,ASIHTTPRequest將向request中增加一個Accept-Encoding頭,表示我們可以接收gzip壓縮過的數據。如果響應頭中包含一個Content-Encoding頭指明數據是壓縮過的,那么調用responseData 或者responseString 將會得到解壓縮后的數據。你也可以通過調用rawResponseData來獲得原始未壓縮的數據。

 

相應數據的實時解壓縮

默認情況下,ASIHTTPRequest會等到request完成時才解壓縮返回的數據。若設置request的shouldWaitToInflateCompressedResponses 屬性為NO,ASIHTTPRequest將會對收到的數據進行實時解壓縮。 在某些情況下,這會稍稍提升速度,因為數據可以在reqeust等待網絡數據時進行處理。

如果你需要對響應數據流進行流處理(例如XML和JSON解析),這個特性會很有用。如果啟用了這個選項,你可以通過實現代理函數request:didReceiveData:來將返回的網絡數據一點一點喂給解析器。

注意,如果shouldWaitToInflateCompressedResponses 被設置為NO,那么原始(未解壓)的數據會被拋棄。具體情況請查閱ASIHTTPRequest.h的代碼注釋。

 

使用gzip壓縮request數據

1.0.3版本的新特性就是gzip壓縮request數據。使用這個特性,你可以通過設置shouldCompressRequestBody 為YES來使你的程序壓縮POST/PUT的內容,默認值為NO。

apache的mod_deflate可以自動解壓縮gzip壓縮的請求體(通過合適的設置)。這個方法適用於CGI內容,但不適用於內容過濾器式的模塊(例如mod PHP),這種情況下,你就必須自己解壓縮數據。

ASIHTTPRequest 無法檢測一個服務器是否能接收壓縮過的請求體。當你確定服務器可以解壓縮gzip包時,再使用這個特性。

請避免對已經壓縮過的格式(例如jpeg/png/gif/pdf/swf)進行壓縮,你會發現壓縮后的數據比原數據更大。(夢維:因為壓縮包都有頭信息)

 
            

ASIHTTPRequest-斷點續傳(下載)

 

從0.94版本開始,ASIHTTPRequest可以恢復中斷的下載

- (IBAction)resumeInterruptedDownload:(id)sender
{
  NSURL *url = [NSURL URLWithString:
    @"http://www.dreamingwish.com/wp-content/uploads/2011/10/asihttprequest-auth.png"];
  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
 
  NSString *downloadPath = @"/Users/ben/Desktop/asi.png";
 
  //當request完成時,整個文件會被移動到這里
  [request setDownloadDestinationPath:downloadPath];
 
  //這個文件已經被下載了一部分
  [request setTemporaryFileDownloadPath:@"/Users/ben/Desktop/asi.png.download"];
  [request setAllowResumeForFileDownloads:YES];
  [request startSynchronous];
 
  //整個文件將會在這里
  NSString *theContent = [NSString stringWithContentsOfFile:downloadPath];
}

這個特性只對下載數據到文件中有效,你必須為一下情況的request設置allowResumeForFileDownloads 為YES:

  • 任何你希望將來可以斷點續傳的下載(否則,ASIHTTPRequest會在取消或者釋放內存時將臨時文件刪除)
  • 任何你要進行斷點續傳的下載

另外,你必須自己設置一個臨時下載路徑(setTemporaryFileDownloadPath),這個路徑是未完成的數據的路徑。新的數據將會被添加到這個文件,當下載完成時,這個文件將被移動到downloadDestinationPath 。

斷點續傳的工作原理是讀取temporaryFileDownloadPath的文件的大小,並使用Range: bytes=x HTTP頭來請求剩余的文件內容。

ASIHTTPRequest並不檢測是否存在Accept-Ranges頭(因為額外的HEAD頭請求會消耗額外的資源),所以只有確定服務器支持斷點續傳下載時,再使用這個特性。



ASIHTTPRequest-直接讀取磁盤數據流的請求體

 

從0.96版本開始,ASIHTTPRequest可以使用磁盤上的數據來作為請求體。這意味着不需要將文件完全讀入內存中,這就避免的當使用大文件時的嚴重內存消耗。

使用這個特性的方法有好幾種:

ASIFormDataRequests

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:@"foo" forKey:@"post_var"];
[request setFile:@"/Users/ben/Desktop/bigfile.txt" forKey:@"file"];
[request startSynchronous];

當使用setFile:forKey:時,ASIFormDataRequests 自動使用這個特性。request將會創建一個包含整個post體的臨時文件。文件會一點一點寫入post體。這樣的request是由CFReadStreamCreateForStreamedHTTPRequest創建的,它使用文件讀取流來作為資源。

普通ASIHTTPRequest

如果你明白自己的request體會很大,那么為這個request設置流式讀取模式。

[request setShouldStreamPostDataFromDisk:YES];

下面的例子中,我們將一個NSData對象添加到post體。這有兩個方法:從內存中添加(appendPostData:),或者從文件中添加(appendPostDataFromFile:);

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setShouldStreamPostDataFromDisk:YES];
[request appendPostData:myBigNSData];
[request appendPostDataFromFile:@"/Users/ben/Desktop/bigfile.txt"];
[request startSynchronous];

這個例子中,我們想直接PUT一個大文件。我們得自己設置setPostBodyFilePath ,ASIHTTPRequest將使用這個文件來作為post體。

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:@"PUT"];
[request setPostBodyFilePath:@"/Users/ben/Desktop/another-big-one.txt"];
[request setShouldStreamPostDataFromDisk:YES];
[request startSynchronous];

IMPORTANT:切勿對使用上述函數的request使用setPostBody——他們是互斥的。只有在你要自己建立request的請求體,並且還准備在內存中保持這個請求體時,才應該使用setPostBody。

 
            

ASIHTTPRequest-使用download cache

 

從1.8版本開始,ASIDownloadCache和ASICacheDelegate的API改變了,你可能需要修改你的代碼。

尤其是,cache策略的可用選項發生了改變,你現在可以對單一request使用結合的cache策略

ASIHTTPRequest可以自動緩存下載的數據。在很多情況下這很有用:

  • 當你離線時,你無法再次下載數據,而你又需要訪問這些數據
  • 從上次下載這些數據后,你只想在數據更新后才下載新的數據
  • 你處理的數據永遠不會發生改變,所以你只想下載一次數據

在之前版本的ASIHTTPRequest里,遇到上述情況,你只能自己處理這些策略。在一些情況下,使用download cache可以讓你不用再寫本地緩存機制。

ASIDownloadCache 是個簡單的URL cache,可以用來緩存GET請求的相應數據。一個request要被緩存,它首先必須請求成功(沒有發送錯誤),服務器必須返回200HTTP狀態值。或者,從1.8.1版本開始,301,302,303,307重定向狀態碼都可以。

要打開響應值的cache機制很簡單:

[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];

這樣做以后,所有的request都會自動使用cache。如果你願意,你可以讓不同的request使用共享的cache:

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadCache:[ASIDownloadCache sharedCache]];

你不會被局限於使用單一的cache,你可以想創建多少cache就創建多少cache,只要你喜歡 ^ ^。當你自己創建一個cache,你必須設定cache的路徑——這路徑必須是一個你擁有寫權限的目錄。

ASIDownloadCache *cache = [[[ASIDownloadCache alloc] init] autorelease];
[cache setStoragePath:@"/Users/ben/Documents/Cached-Downloads"];

//別忘了 - 你必須自己retaining你自己的cache!
[self setMyCache:cache];

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadCache:[self myCache]];

cache策略

cache策略是你控制cache中信息的主要方法,控制何時使用cache數據而非重新下載數據。

每個request的cache策略可是由request的cachePolicy 屬性來控制的。cache策略使用掩碼來定義,所以你可以二進制“與”操作他們。

// 每次都向服務器詢問是否有新的內容可用,
// 如果請求失敗, 使用cache的數據,即使這個數據已經過期了
[request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy];

你可以使用下列cache策略選項來控制request的緩存策略:

ASIUseDefaultCachePolicy

默認的cache 策略。請勿將這一項與其他項結合使用。當你設置一個request使用cache,它會使用cache的defaultCachePolicy. ASIDownloadCache的默認cache策略是‘ASIAskServerIfModifiedWhenStaleCachePolicy’. 

ASIDoNotReadFromCacheCachePolicy

使用這一項,request將不會從cache中讀取數據

ASIDoNotWriteToCacheCachePolicy

使用這一項,request將不會把數據存入cache

ASIAskServerIfModifiedWhenStaleCachePolicy

這是ASIDownloadCaches的默認cache策略。使用這個策略時,request會先查看cache中是否有可用的緩存數據。如果沒有,request會像普通request那樣工作。

如果有緩存數據並且緩存數據沒有過期,那么request會使用緩存的數據,而且不會向服務器通信。如果緩存數據過期了,request會先進行GET請求來想服務器詢問數據是否有新的版本。如果服務器說緩存的數據就是當前版本,那么緩存數據將被使用,不會下載新數據。在這種情況下,cache的有效期將被設定為服務器端提供的新的有效期。如果服務器提供更新的內容,那么新內容會被下載,並且新的數據以及它的有效期將被寫入cache。

ASIAskServerIfModifiedCachePolicy

這一項與ASIAskServerIfModifiedWhenStaleCachePolicy相同,除了一點:request將會每次都詢問服務器端數據是否有更新。

ASIOnlyLoadIfNotCachedCachePolicy

使用這一項,cache數據將一直被使用,無視過期時間

ASIDontLoadCachePolicy

使用這一項時,只有當響應數據有緩存時,request才會成功。如果一個request沒有緩存的響應數據,那么這個request將會停止,並且不會有錯誤設置在request上。

ASIFallbackToCacheIfLoadFailsCachePolicy

當使用這一項時,當request失敗時,request會回頭請求cache數據。如果請求失敗后,request使用的cache數據,那么這個request會成功(沒有錯誤)。你通常會將這一項與其他項結合使用,因為它適用於指定當發生錯誤時request的行為。

 

當你設定了一個cache對象的defaultCachePolicy 屬性,所有使用這個cache對象的request都會使用這個cache策略,除非你為request設置了另外的策略。

存儲策略

存儲策略允許你定義一個cache可以存儲特定的相應數據多久。ASIHTTPRequest目前支持兩種存儲策略:

ASICacheForSessionDurationCacheStoragePolicy是默認值。相應數據只會在會話期間被存儲,在第一次使用cache時,或者在調用 [ASIHTTPRequest clearSession]時,數據會被清除。

使用ASICachePermanentlyCacheStoragePolicy,緩存的相應數據會被永久存儲。要使用這個存儲策略,向request設置:

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];

要手動清除cache,調用函數clearCachedResponsesForStoragePolicy:,傳入要清除的cache數據的存儲策略:

[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICachePermanentlyCacheStoragePolicy];

其他cache相關的特性

// 當你關閉 shouldRespectCacheControlHeaders,cache對象會存儲響應數據,而無視
// 服務器的顯式“請勿緩存”聲明 (例如:cache-control 或者pragma: no-cache 頭)
[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];

// 可以設定request的secondsToCache來覆蓋服務器設定的內容有效期, 這時,響應數據
// 會一直被緩存,直到經過secondsToCache秒
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setSecondsToCache:60*60*24*30]; // 緩存30 天

//當request開始執行后,如果響應數據是從緩存中取得的,didUseCachedResponse 會返回YES
[request didUseCachedResponse];

// 向cache對象索取一個路徑來存儲相應數據. 這是使用download cache的最有效率的方法,
// 因為此時,當request完成后,數據不需要被復制到cache中.
[request setDownloadDestinationPath:
   [[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request]];

編寫自己的cache

如果你已經持有一個download cache並且想將他插入ASIHTTPRequest中,或者你喜歡自己寫自己的download cache,那么讓你的cache實現ASICacheDelegate協議。

 

ASIHTTPRequest-流量控制

 

從1.0.7版本開始,ASIHTTPRequest可以控制流量,使得所有request的流量不會超過用戶定義的限制范圍。這可以使得發送/接收大量數據的iphone程序更容易通過蘋果的app store的審核。

流量是由一個全局的數量限制(字節)來控制的——每秒鍾可以傳送多少流量的數據。所有request共享這個限制。在發送或接收數據時,ASIHTTPRequest保持追蹤上一秒所發送/接收的數據量。如果一個request達到了限制,其他正在執行的request將會等待。 在iOS上,你可以讓ASIHTTPRequest在使用WWAN (GPRS/Edge/3G) 連接時自動打開流量控制,而當使用WiFi連接時自動關閉流量限制。

// 這將會對WWAN連接下的request進行流量控制(控制到預定義的值)
// Wi-Fi連接下的 request不會受影響
// 這個方法僅在iOS上可用
[ASIHTTPRequest setShouldThrottleBandwidthForWWAN:YES];
 
// 這將會對WWAN連接下的request進行流量控制(控制到自定義的值)
// 這個方法僅在iOS上可用
[ASIHTTPRequest throttleBandwidthForWWANUsingLimit:14800];
 
// 這將會控移動應用(mobile applications)的流量到預定義的值.
// 會限制所有requests, 不管request是不是WiFi連接下的 - 使用時要注意
[ASIHTTPRequest setMaxBandwidthPerSecond:ASIWWANBandwidthThrottleAmount];
 
// 記錄每秒有多少字節的流量 (過去5秒內的平均值)
NSLog(@"%qi",[ASIHTTPRequest averageBandwidthUsedPerSecond]);

IMPORTANT:在啟用流量控制前,請參閱以下條目:

 
              
  • 流量控制特性是試驗型的特性:你自己得承擔風險
  • 不要把帶寬限制設置得很低——最好不要低於ASIWWANBandwidthThrottleAmount
  • 實際流量往往會比你程序設置的流量稍稍偏高,因為流量的測量並不包含HTTP頭。
  • ASIWWANBandwidthThrottleAmount 的值是非官方的,據我所知,官方並沒有公布流量限制大小
  • 除非你的程序會下載或者上傳大量的數據,否則不要開啟流量控制。最好是當即將下載或上傳大量數據時才啟用它,而其他時間應該禁用它。
  • 這玩意應該會按我描述的情況來工作,但是我並不保證你的app使用了我的流量控制就不會被駁回。
 

ASIHTTPRequest-客戶端證書支持

有時服務器要求提供客戶端證書,從1.8版本開始,你可以隨request發送證書。
// Will send the certificate attached to the identity (identity is a SecIdentityRef)
[request setClientCertificateIdentity:identity];
 
// Add an additional certificate (where cert is a SecCertificateRef)
[request setClientCertificates:[NSArray arrayWithObject:(id)cert]];

在iPhone/iPad示例工程中的ClientCertificateTests.m中有一個很有用的函數用來從PKCS12數據創建SecIdentityRef (這個函數僅適用於iOS)。

 

ASIHTTPRequest-使用代理連接

 
              

ASIHTTPRequest檢測系統的proxy設置並自動將proxy用於request。從1.0.6版本開始,它還支持PAC文件和要求授權的proxy。

默認情況下,ASIHTTPRequest將嘗試自動檢測proxy設置。當然,你可以看自己手動設置:

// 手動設置代理服務器
NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setProxyHost:@"192.168.0.1"];
[request setProxyPort:3128];

// 另一種方法, 使用代理配置腳本文件
// (最好使用本地pac文件)
[request setPACurl:[NSURL URLWithString:@"path/to/test.pac"]];

要求授權的proxy

在Mac OS上,ASIHTTPRequest可以自動檢測到要求授權的proxy的憑據(前提是在系統設定中設置好)。在iOS上,ASIHTTPRequest則無法自動檢測出授權憑據,所以你要么手動使用delegate來向你的controller或者用戶索取合適的憑據,要么讓ASIAuthenticationDialog向用戶索取憑據。一旦獲得了一個有效的proxy憑據,那么該憑據將被存儲到keychian中(前提是啟用useKeychainPersistence )並自動重用。

手動為proxy指定憑據

NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setProxyHost:@"192.168.0.1"];
[request setProxyPort:3128];

//為要求授權的proxy設置username 和password
[request setProxyUsername:@"bencopsey"];
[request setProxyPassword:@"password"];

// 對於NTLM proxy,還要設置 domain (NTLM proxy功能是未經測試的)
[request setProxyDomain:@"la.la.land"];

使用delegate來提供proxy憑據

這個特性的工作原理和“使用delegate提供HTTP授權”一樣,只有一點不同:你的delegate要響應proxyAuthenticationNeededForRequest:函數。

asihttprequest授權對話框

使用內建的授權對話框(僅適用於iOS)

這個特性歸功於1.0.8版本的新類ASIAuthenticationDialog 。用來向用戶索取憑據來授權webserver或者proxy。

如果你的delegate不響應proxyAuthenticationNeededForRequest:函數,那么默認情況下,ASIHTTPRequest將會顯示一個對客戶來提示用戶輸入授權憑據。使用ASIHTTPRequest,開發者不再需要寫額外的代碼來顯示授權對話框,因為默認情況下,ASIHTTPRequest就會顯示它。

使用同步request時proxy授權對話框不會顯示出來。

如果你不限使用proxy授權對話框,那么你要么實現proxyAuthenticationNeededForRequest:,要么設置shouldPresentProxyAuthenticationDialog 為false(此時你的程序將無法連接到proxy)。如果你要改變對話框的樣式,你得繼承ASIHTTPRequest類,重寫showProxyAuthenticationDialog 來顯示你自己的對話框或者ASIAuthenticationDialog 子類.

 

ASIHTTPRequest-其他特性

 

設置user agent

這樣設置用戶代理:

[ASIHTTPRequest setDefaultUserAgentString:@"MyApp 1.0"]

如果不設置user agent,ASIHTTPRequest會為你創建一個。例如(Mac OS程序):

My Application 1.0 (Macintosh; Mac OS X 10.5.7; en_GB)

你也可以為每個request設置user agent:

[request setUserAgent:@"MyApp 1.0"]

當程序進入后台運行時,繼續執行request(iOS)

// iOS 4以上
[request setShouldContinueWhenAppEntersBackground:YES];

監視網絡活動

//記錄過去5秒的平均流量字節/秒
NSLog(@"%llu",[ASIHTTPRequest averageBandwidthUsedPerSecond]);
 
if ([ASIHTTPRequest isNetworkInUse]) {
	// ASIHTTPRequest 進程中有requests正在使用網絡
}

禁用自動更新網絡連接標示符狀態(iOS)

默認情況下,ASIHTTPRequest在request使用網絡連接時,會自動顯示網絡連接標示符(iOS狀態條中)。如果你想自己控制標示符,你可以禁用這個特性:

[ASIHTTPRequest setShouldUpdateNetworkActivityIndicator:NO];

超時自動重試

設置超時自動重試最大次數為2:

[request setNumberOfTimesToRetryOnTimeout:2];

設置持久連接

默認情況下,ASIHTTPRequest將會嘗試保持對一個服務器的連接以便往后的連接到該服務器的request可以重用這個連接(這個特性可以顯著地提高速度,尤其是當你會要進行很多小數據量request時)。當連接到HTTP 1.1服務器或者服務器發送keep-alive頭時,持久連接會自動被使用。當服務器顯式地發送”Connection:close”頭時,持久連接就不會被使用。另外,默認情況下,ASIHTTPRequest不會對包含請求體(例如POST/PUT)的request使用持久連接(從1.8.1版本開始)。通過設置request,你可以強制讓此類request使用持久連接:

[request setRequestMethod:@"PUT"];
[request setShouldAttemptPersistentConnection:YES];

很多服務器不會在響應頭中規定持久連接的持久時間,它們可能會在任何一個request完成時候關閉連接。如果一個服務器沒有規定持久連接的持久時間,ASIHTTPRequest將會在一個request完成后,保持連接60秒。對於你的服務器設置來時,60可能很長,也可能很短。

如果這個超時時間太長,那么可能一個request使用這個連接時,服務器可能已經關閉了這個連接。當ASIHTTPRequest遇到連接已關閉錯誤,它就會在一個新的連接上重試這個request。

如果這個超時時間太短,而服務器卻更想讓這個連接保持更長時間,但是ASIHTTPRequest又開啟了不必要的新連接,那么這將導致效率降低。

// 設置持久連接的超時時間為120秒
[request setPersistentConnectionTimeoutSeconds:120];
 
// 徹底禁用持久連接
[request setShouldAttemptPersistentConnection:NO];

強制使用HTTP 1.0

[request setUseHTTPVersionOne:YES];

禁用安全證書校驗

如果你有一個自簽名的證書,你可能想禁用證書校驗來做測試。這里我建議你從一個可信的CA購買證書,並為生產(production)期的app(夢維:app還有測試期等等階段不是?)啟用證書校驗。

[request setValidatesSecureCertificate:NO];

ASIHTTPRequest-Debug選項

 

ASIHTTPRequest提供少量的有助於調試request行為的宏標記。這些宏可以從ASIHTTPRequestConfig.h文件中找到。

當打開這些標志時,request將會打印一些信息到控制台,顯示它們正在做什么。

DEBUG_REQUEST_STATUS

打印request的生命周期的所有信息,開始,結束上載,結束下載。

DEBUG_THROTTLING

打印request使用了多少流量(大致),如果request的流量被控制,打印如何被控制。當與DEBUG_REQUEST_STATUS結合使用時,這一項可以用來調試“超時”,你可以看到request停止發送或接收數據的時間點。

DEBUG_PERSISTENT_CONNECTIONS

打印request如何重用持久連接的信息,如果你看到這樣的信息:

Request attempted to use connection #1, but it has been closed – will retry with a new connection

這說明你設置的persistentConnectionTimeoutSeconds 太大了。

DEBUG_HTTP_AUTHENTICATION

1.8.1版本的新特性:開啟這一項會打印request如何處理HTTP授權(Basic,Digest或者NTLM)的相關信息。

DEBUG_FORM_DATA_REQUEST

打印出ASIFormDataRequest將發送的整個request體。使用ASIFormDataRequest時,這一項很有用。





 

升級到iOS5后ASIHttpRequest庫問題及解決方法

 
              
 

由於正式版的iOS5出來了,所以我也試着去升級了。於是下載了最新的Xcode,才1.7G左右,比以往的安裝包要小許多。

升級Xcode后,打開以前創建的工程, 運氣好,一個錯誤都沒有,程序也能正常跑起來。由於我程序中用了ASIHttpRequest這個庫,讓我發現了一個小問題,就是

ASIAuthenticationDialog這個內置對話框在網絡有代理的情況下出現,然后無論點cancle或是login都不能dismiss。在4.3的SDK中完全沒問題,在5.0的SDK中就會在Console中看到輸出:

Unbalanced calls to begin/end appearance transitions for <ASIAutorotatingViewController:>

很明顯示在sdk5中, 用這個庫有問題,還有在停止調式的時候,程序會有異常產生。

 

於是很明顯示是SDK5的變化影響了ASIHttpRequest的正常使用。於是我要fix這個問題,經過我研究發現,dismiss不起作用是由於UIViewController的parentViewController不再返回正確值了,返回的是nil,而在SDK5中被presentingViewController取代了。於是在ASIAuthenticationDialog.m中找到+(void)dismiss這個方法並修改為:

 

  1. + (void)dismiss  
  2. {  
  3. #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_4_3  
  4.     UIViewController *theViewController = [sharedDialog presentingViewController];  
  5.     [theViewController dismissModalViewControllerAnimated:YES];  
  6. #else  
  7.     UIViewController *theViewController = [sharedDialog parentViewController];  
  8.     [theViewController dismissModalViewControllerAnimated:YES];  
  9. #endif  
  10. }  

 

這樣編譯出來的程序能在ios5設備上正確運行,但是在ios5以下的設備則會crash。因為是庫,所以要考慮到兼容不同版本,於是進一步修改為:

 

  1. + (void)dismiss  
  2. {  
  3. #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_4_3  
  4.     if ([sharedDialog respondsToSelector:@selector(presentingViewController)])   
  5.     {  
  6.         UIViewController *theViewController = [sharedDialog presentingViewController];  
  7.         [theViewController dismissModalViewControllerAnimated:YES];  
  8.     }  
  9.     else  
  10.     {  
  11.         UIViewController *theViewController = [sharedDialog parentViewController];  
  12.         [theViewController dismissModalViewControllerAnimated:YES];  
  13.     }  
  14. #else  
  15.     UIViewController *theViewController = [sharedDialog parentViewController];  
  16.     [theViewController dismissModalViewControllerAnimated:YES];  
  17. #endif  
  18. }  


還有上面那個Console的錯誤提示,解決方法是,在ASIAuthenticationDialog.m中找到-(void)show這個方法,並把最后一行代碼

 

 

  1. [[self presentingController] presentModalViewController:self animated:YES];  

修改為:

 

 

  1. UIViewController *theController = [self presentingController];  
  2.       
  3. #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_4_3  
  4.     SEL theSelector = NSSelectorFromString(@"presentModalViewController:animated:");  
  5.     NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:[[theController class] instanceMethodSignatureForSelector:theSelector]];  
  6.       
  7.     [anInvocation setSelector:theSelector];  
  8.     [anInvocation setTarget:theController];  
  9.       
  10.     BOOL               anim = YES;  
  11.     UIViewController   *val = self;  
  12.     [anInvocation setArgument:&val atIndex:2];  
  13.     [anInvocation setArgument:&anim atIndex:3];  
  14.       
  15.     [anInvocation performSelector:@selector(invoke) withObject:nil afterDelay:1];  
  16. #else  
  17.       
  18.     [theController presentModalViewController:self animated:YES];  
  19. #endif  

這下就可以正常運行了喲, 我的問題也解決了。關於ASIHttpRequest的其它方面,到目前為止還沒發現問題。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM