Creating a synchronous request

可以创建同步和异步两种方式的请求,一般情况下应当使用异步请求。使用同步请求主应用线程会锁住直至解锁为止。

  • 创建异步请求,会在后台执行
- (IBAction)grabURLInBackground:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://allseeing-i.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];
}
这里我们设置了代理,就可以接收状态了。
  • Using blocks

- (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];
} 这里使用__block很重要,告诉block不要retain这个请求,可以防止retain-cycle因为request经常会retain block
  • Using a queue

可以利用NSOperationQueue创建队列,当使用队列时在同一时间只有一定数量的请求可以执行。如果添加的请求多余队列的maxConcurrentOperationCount属性,那么其余的请求会等待其他请求执行完毕才会开始执行。
- (IBAction)grabURLInTheBackground:(id)sender
{
if (![self queue]) {
[self setQueue:[[[NSOperationQueue alloc] init] autorelease]];
}
 
NSURL *url = [NSURL URLWithString:@"http://allseeing-i.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 requestDone requestWentWrong 如果不自定义的话那么默认的方法requestFinishedrequestFailed会被执行
  • About ASINetworkQueues

ASINetworkQueue是NSOperationQueue的子类提供一些其他的功能:主要的功能是允许跟踪整个队列的上传和/或下载进度。
此外,还提供一些额外的delegate方法:
    • requestDidStartSelector
      Called each time a request in the queue begins running. You can use this
      as an alternative to specifying a didStartSelector and setting a
      delegate on requests you add to the queue
    • requestDidReceiveResponseHeadersSelector
      Called each time a request in the queue receives response headers from
      the server. For large downloads, this may be some time before the
      request actually completes. You can use this as an alternative to
      specifying a didReceiveResponseHeadersSelector and setting a delegate on
      requests you add to the queue
    • requestDidFinishSelector
      Called each time a request in the queue completes successfully. You can
      use this as an alternative to specifying a didFinishSelector and setting
      a delegate on requests you add to the queue
    • requestDidFailSelector
      Called each time a request in the queue fails. You can use this as an
      alternative to specifying a didFailSelector and setting a delegate on
      requests you add to the queue
    • queueDidFinishSelector
      Called when the whole queue has completed, whether individual requests failed or succeeded.

如果想使用上面的delegate就需要为queque而不是request来设置delegate了。ASINetworkQueues和NSOperationQueues是不同的,所有的请求不会立即执行。当使用ASINetworkQueues时,添加所有的请求,然后执行[queue go]当开始队列后,首先会执行head请求来获得要下载的数据总大小,一旦获得了总大小,就能真正显示总进度并开始真正的请求。

当使用ASINetworkQueue来跟踪整个请求进度时,只有当请求开始运行时,才会在后退计算各个新请求的进度。当队列开始后再添加新的请求,那么ASINetworkQueue是不会执行head请求的,所以如果你为一个已经执行的队列添加多个请求,那么整体的进度是不会立即更新的。

如果队列已经开启,那么就不需要再执行[queue go]

当一个ASINetworkQueue中的请求失败了,那么默认的其他的请求都会cancel,如果想去掉这个功能,那么就设置[queue setShouldCancelAllRequestsOnFailure:NO].

下面是一个例子来描述如何使用ASINetworkQueue

http://gist.github.com/150447

源代码如下:

//
// MyController.h
//
// Created by Ben Copsey on 20/07/2009.
// Copyright 2009 All-Seeing Interactive. All rights reserved.
//
 
#import <Foundation/Foundation.h>
#import <GHUnit/GHUnit.h>
@class ASINetworkQueue;
 
@interface MyController : NSObject {
ASINetworkQueue *networkQueue;
 
}
 
- (void)doNetworkOperations;
 
@property (retain) ASINetworkQueue *networkQueue;
 
@end
 
-------------------------------------------------------------------
 
//
// MyController.m
//
// Created by Ben Copsey on 20/07/2009.
// Copyright 2009 All-Seeing Interactive. All rights reserved.
//
 
#import "MyController.h"
#import "ASIHTTPRequest.h"
#import "ASINetworkQueue.h"
 
@implementation MyController
 
- (void)dealloc
{
[networkQueue release];
[super dealloc];
}
 
- (void)doNetworkOperations
{
// Stop anything already in the queue before removing it
[[self networkQueue] cancelAllOperations];
 
// Creating a new queue each time we use it means we don't have to worry about clearing delegates or resetting progress tracking
[self setNetworkQueue:[ASINetworkQueue queue]];
[[self networkQueue] setDelegate:self];
[[self networkQueue] setRequestDidFinishSelector:@selector(requestFinished:)];
[[self networkQueue] setRequestDidFailSelector:@selector(requestFailed:)];
[[self networkQueue] setQueueDidFinishSelector:@selector(queueFinished:)];
 
int i;
for (i=0; i<5; i++) {
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com"]];
[[self networkQueue] addOperation:request];
}
 
[[self networkQueue] go];
}
 
- (void)requestFinished:(ASIHTTPRequest *)request
{
// You could release the queue here if you wanted
if ([[self networkQueue] requestsCount] == 0) {
 
// Since this is a retained property, setting it to nil will release it
// This is the safest way to handle releasing things - most of the time you only ever need to release in your accessors
// And if you an Objective-C 2.0 property for the queue (as in this example) the accessor is generated automatically for you
[self setNetworkQueue:nil];
}
 
//... Handle success
NSLog(@"Request finished");
}
 
- (void)requestFailed:(ASIHTTPRequest *)request
{
// You could release the queue here if you wanted
if ([[self networkQueue] requestsCount] == 0) {
[self setNetworkQueue:nil];
}
 
//... Handle failure
NSLog(@"Request failed");
}
 
 
- (void)queueFinished:(ASINetworkQueue *)queue
{
// You could release the queue here if you wanted
if ([[self networkQueue] requestsCount] == 0) {
[self setNetworkQueue:nil];
}
NSLog(@"Queue finished");
}
 
@synthesize networkQueue;
@end
  • Handling success and failure for multiple requests in delegate methods

如果想控制不同类型请求的成功和失败结果,可以有多个方法:
1,如果请求的类型相同,想加以区分,那么就可以为每个请求设置userinfo 这个nsdictionary属性,为了简便起见,可以直接设置请求的tag属性来标记。userinfo和tag都不会发送给服务器,只供给本地使用。
2,如果想为每个请求都单独设置各自的成功和失败操作,那么可以自定义方式来setDidFinishSelector / setDidFailSelector
3, 如果是更为复杂的操作,那么可以为每个种类的请求分别写一个ASIHTTPRequest的子类来重写requestFinished: and failWithError:
注意:这里需要避免使用url来作为区别不同请求的方式,因为这个url可能会随着重定向而改变。所以如果真的想使用url,那么就要使用[request originalURL]来代替。这个方法会始终使用原始的第一个url
  • Cancelling an asynchronous request

使用[request cancel]方法来取消请求,但是不能cancel一个同步的请求

如果你取消了一个请求,那么默认的会把这个动作视为error,就会调用failure delegate。所以,如果想避免这个调用,可以设置delegate为nil或者使用clearDelegatesAndCancel方法来替代

当ASINetworkQueue中有一个request被cancel掉了,那么默认的其他的都会cancel,除非之前设置了shouldCancelAllRequestsOnFailure为no

// Cancels an asynchronous request
[request cancel]
 
// Cancels an asynchronous request, clearing all delegates and blocks first
[request clearDelegatesAndCancel];
// When a request in this queue fails or is cancelled, other requests will continue to run
[queue setShouldCancelAllRequestsOnFailure:NO];
 
// Cancel all requests in a queue
[queue cancelAllOperations];
  • Safely handling the delegate being deallocated before the request has finished

// Ddealloc method for our controller
- (void)dealloc
{
[request clearDelegatesAndCancel];
[request release];
...
[super dealloc];
}
  • Sending data

Setting request headers

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request addRequestHeader:@"Referer" value:@"http://allseeing-i.com/"];

Sending a form POST with ASIFormDataRequest

To send POST data in a manner compatible with web page forms, use the included ASIFormDataRequest subclass. Data is posted in ‘application/x-www-form-urlencoded’ format, or ‘multipart/form-data’ format when uploading binary data or files. Data in files is read as needed from disk, so POSTing large files is OK, as long as your web server is setup to handle them.

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"];

ASIFormDataRequest will autodetect the mime type of files (on iOS 3.0 or later an Mac) added to the POST via setFile:forKey:, and include this in the mime headers sent to the server. If you prefer, you can use the longer form to override this:

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"];
 

You can send multiple values for the same parameter using the alternative add API:

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"];

See ASIFormDataRequest.h for a full list of all the ways to add parameters to your POST.

PUT requests and custom POSTs

If you want to send data via PUT, or want to send it with POST but prefer to create the POST body yourself, use appendPostData: or 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"];

If you want to send large amounts of data and aren’t using an ASIFormDataRequest, see the information on streaming post bodies from disk below.

  • Downloading data

Downloading the response directly to a file

  1. 如果下载的资源过大,为了节省内存空间可以考虑直接下载到文件中去。这种方法将数据暂时存放再临时文件中,这个临时文件路径保存在temporaryFileDownloadPath中。当请求完成后,会发生:
  2. 如果数据是gzip压缩形式的(see information on gzip compression),那么会将文件解压缩到downloadDestinationPath中然后删除掉临时文件。
  3. 如果数据不是压缩形式的,那么临时文件会被移动到downloadDestinationPath中覆盖任何之前的文件。

注意,如果response body是空的,那么就不会有文件被创建。所以最好先判断文件是否是空的然后再对其进行操作。

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

Handling the response data as it arrives

如果你需要在数据接收时进行一些操作,比如想一边接收一边用streaming parser来解析数据,那么就自己执行request:didReceiveData:。注意:当你这样执行后,ASIHTTPRequest不会产生responsedata或者将data写到downloadDestinationPath中去。你必须子阿吉存储文件。

Reading the HTTP status code

ASIHTTPRequest不会对http大多数的status codes做特殊处理,(除非重定向和认证status codes),所以需要你自己检查诸如404错误并保证之前的操作是对的。

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

Reading response headers

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

Handling text encodings

ASIHTTPRequest will attempt to read the text encoding of the received data from the Content-Type header. If it finds a text encoding, it will set responseEncoding to the appropriate NSStringEncoding. If it does not find a text encoding in the header, it will use the value of defaultResponseEncoding (this defaults to NSISOLatin1StringEncoding).

When you call [request responseString], ASIHTTPRequest will attempt to create a string from the data it received, using responseEncoding as the source encoding.

Handling redirection

ASIHTTPRequest will automatically redirect to a new URL when it encounters one of the following HTTP status codes, assuming a Location header was sent:

  • 301 Moved Permanently
  • 302 Found
  • 303 See Other

When redirection occurs, the value of the response data (responseHeaders / responseCookies / responseData / responseString etc) will reflect the content received from the final location.

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.

You can turn off automatic redirection by setting the request’s shouldRedirect property to NO.

By default, automatic redirects always redirect using a GET request (with no body). This behaviour matches the way most browsers work, not the HTTP spec, which specifies that 301 and 302 redirects should use the original method.

To preserve the original method (including the request body) for 301 and 302 redirects, set shouldUseRFC2616RedirectBehaviour to YES on the request before you start it.

Tracking progress

每一个ASIHTTPRequest有两个代理来跟踪进度,downloadProgressDelegate和uploadProgressDelegate

进度代理可以是NSProgressIndicators (Mac OS X) or UIProgressViews (iPhone). 你也可以使用自定义的类作为progress delegate,只要他实现了setProgress:

  1. 如果正在执行单个request,那么就要设置upload 或/和 download progress delegate
  2. 如果正在执行多个request在队列中,那么就需要为整个队列设置progress
  3. 如果想同时为以上两种情况设置progress也是可以的

IMPORTANT: If you are uploading to a site that requires authentication, the upload progress will be reset to its previous value every time it fails to supply valid authentication. For this reason, it is recommended that you only ever use an upload progress delegate when useSessionPersistence is YES (see below) when communicating with authenticating web servers, and ensure that you authenticate in another request before attempting to track the upload of a large amount of data.

Tracking progress for uploads where the request body is less than 128KB is currently not possible. For requests larger than 128KB, progress delegates will not receive information on the progress of the first 128KB of post data. This is because of limitations in the CFNetwork API. I have filed a feature enhancement with Apple (bug id 6596016), hopefully they will modify CFNetwork in future to make this possible.

Update 21st June 2009: The wonderful folks at Apple were kind enough to address my bug report! In the iPhone 3.0 SDK, it looks like the buffer size has been reduced to 32KB, which makes accurate upload progress tracking a lot more reliable.

Tracking download progress for a single request

In this example, myProgressIndicator is an NSProgressIndicator.

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

Tracking download progress for a set of requests

In this example, myProgressIndicator is an UIProgressView, myQueue is an ASINetworkQueue.

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

Tracking upload progress for a single request

In this example, myProgressIndicator is an 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]);

Tracking upload progress for a set of requests

In this example, myProgressIndicator is an NSProgressIndicator, myQueue is an ASINetworkQueue.

- (void)uploadSomethingFiveTimes:(NSURL *)url
{
[myQueue cancelAllOperations];
[myQueue setUploadProgressDelegate:myProgressIndicator];
[myQueue setDelegate:self];
[myQueue setRequestDidFinishSelector:@selector(queueComplete:)];
int i;
for (i=0; i<; 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]);
}

Accurate progress vs simple progress

ASIHTTPRequest provides two approaches for displaying progress, simple progress, and accurate progress. They are controlled using the showAccurateProgress of ASIHTTPRequests and ASINetworkQueues. When you set showAccurateProgress on a request, it affects only that request. When you set it on a queue, it affects all requests in the queue.

Simple progress

When using simple progress, progress will update only when a request completes. For a single request, this means you get two progress updates - 0% complete, and 100% complete. For a queue with four requests, you would get five progress updates, 0%, 25%, 50%, 75% and 100%, with each increment representing a request that has completed.

Simple progress (showAccurateProgress = NO) is the default for ASINetworkQueues, and is well suited to queues with a large number of small uploads / downloads.

Accurate progress

When using accurate progress, progress will be updated as bytes are sent or received. It is best for requests that send or receive a large amount of data, and will give a much better indication of how much data has been sent or received for requests that take some time.

Using accurate progress will slightly degrade the performance of uploads, since progress delegates (which are likely to be UIProgressViews or NSProgressIndicators) will be redrawn much more frequently.

Using accurate progress has a much greater effect on performance for downloads when using a queue, since the queue will first perform a HEAD request for each GET request it contains so it can determine the overall size of the data to be downloaded before downloading commences. Using accurate progress is highly recommended if you are downloading large files from a queue, but you should avoid it for queues that contain a large number of small downloads.

Accurate progress (showAccurateProgress == YES) is the default for ASIHTTPRequests that run synchronously.

Custom progress tracking

大多数情况下,设置uploadProgressDelegate and/or downloadProgressDelegate to an NSProgressIndicator or UIProgressView。如果想执行更为复杂的进度跟踪的话,delegates应该实现方法setProgress: (iOS) or setDoubleValue: / setMaxValue: (Mac).这些方法使你得到发送或接收时确切的字节数。

Methods for downloadProgressDelegates

  • request:didReceiveBytes: will be called on your downloadProgressDelegate each time the request downloads a bit more data. (Note that this is distinct from the request:didReceiveData: method that you regular delegate may implement). 当有数据下载接收时就会调用到。
  • request:incrementDownloadSizeBy: will be called when the size of the download changes, with the passed parameter being the amount you should increase the size of the download by. This usually happens when the request receives response headers and finds out the size of the download. 当下载数据大小发生变化时调用此方法。参数就是需要增加的大小。

Methods for uploadProgressDelegates

  • request:didSendBytes: will be called on your uploadProgressDelegate each time the request has been able to send a bit more data. Important: This method will be called with a number less than zero when a request needs to remove upload progress (usually when it has uploaded the data, but failed authentication or needs to run again for some other reason). 因为括号中的这些情况所以上传的大小可能是负数
  • request:incrementUploadSizeBy: will be called when the size of the upload changes. The passed size will frequently be below zero, as the request adjusts the upload size to take account of the size of the internal buffer used by the OS.
  • Handling HTTP authentication

If you’re connecting to a server that requires authentication, you might want to take a look at this flowchart that shows how ASIHTTPRequest finds and applies credentials to requests.

Specifying a username and password to use in the URL

NSURL *url = [NSURL URLWithString:@"http://username:password@allseeing-i.com/top_secret/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

Setting a username and password to use on the request

NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com/top_secret/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUsername:@"username"];
[request setPassword:@"password"];

Storing credentials in the keychain

If you turn on keychainPersistence, any valid username and password supplied will be stored in the keychain. Subsequent requests will reuse the username and password from the keychain, even if you quit and relaunch the application.

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

If you want to use the keychain but would rather manage it yourself, you might find the class methods relating to the keychain in ASIHTTPRequest.h helpful.

Storing credentials in the session

If useSessionPersistence is turned on (it is by default), ASIHTTPRequest stores credentials in memory and can re-use them for subsequent requests.

NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com/top_secret/"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUsername:@"username"];
[request setPassword:@"password"];
[request setUseSessionPersistence:YES]; //Shouldn't be needed as this is the default
 
//Should reuse our username and password
request = [ASIHTTPRequest requestWithURL:url];

NTLM authentication

To authenticate with a Windows server that uses the NTLM scheme, you also need to specify the domain you are authenticating against.

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

Using delegation to provide credentials

Rather than specifying authentication credentials in advance, you might prefer to let each request ask its delegate for credentials if it can’t find them in the session authentication cache or keychain. This might be helpful if you want to connect to a server where you aren’t sure in advance what kind of authentication (if any) will be required.

Make sure your delegate implements authenticationNeededForRequest:, and ASIHTTPRequest will pause a request while it waits for the delegate to let it know what credentials to use. When you have the credentials you need, simply set them on the request, and call [request retryUsingSuppliedCredentials];. If you want to cancel, you must call [request cancelAuthentication]. This will cancel the request.

As of v1.0.8, request delegates will only receive one authenticationNeededForRequest: or proxyAuthenticationNeededForRequest: at once. Other requests requiring authentication will pause while the delegate handles the first request. If credentials are provided, any other requests currently in progress will attempt to reuse them, assuming they are valid for the url. If the delegate cancels authentication, and the queue’s shouldCancelAllRequestsOnFailure is YES, all the other requests will cancel without attempting to ask for credentials.

You cannot use the delegation pattern for authentication when using synchronous requests.

In older versions this would have caused your app to hang, as of v1.0.8 the delegate methods will no longer be called.

Using the built-in authentication dialog (currently iOS only)

New in v1.0.8 is the ASIAuthenticationDialog class. This is primarily used for working with authenticating proxies (see below), but it can be used to ask the user for credentials for authenticating webservers.

For the best user experience, most apps that connect to a single service should implement authenticationNeededForRequest: in their request delegates, or avoid the use of delegation-style authentication altogether. However, there may be some occasions when the use of ASIHTTPRequest’s standard authentication dialog for regular authentication may be advantageous:

  • You don’t want to create your own login form
  • You may need to fetch data from an external source, and aren’t certain if it will require authentication or not

For these cases, set shouldPresentAuthenticationDialog to true on your requests, and, if your delegate does not implement authenticationNeededForRequest:, users will see the dialog.

Only one dialog can appear at once, and other requests requiring authentication will pause while the dialog is visible. If credentials are provided, any other requests currently in progress will attempt to reuse them, assuming they are valid for the url. If the delegate cancels authentication, and the queue’s shouldCancelAllRequestsOnFailure is YES (as per the default), all the other requests will cancel without attempting to ask for credentials.

The authentication dialog will not appear for synchronous requests.

The dialog is partly modelled on the authentication dialog that Safari uses on the iPhone, and includes:

  • A message to indicate these credentials are for a webserver (as opposed to a proxy)
  • The hostname or IP of the server you are connecting to
  • The authentication realm (if one was supplied)
  • Fields to enter a username and password
  • When connecting to a server that uses the NTLM scheme, the dialog also includes a field for the domain
  • A note about whether the credentials are sent in plain text or not (ie: They are sent in plain text only when using Basic authentication without SSL)

If you want to change the look and feel, subclass ASIHTTPRequest, and override showAuthenticationDialog to show your custom dialog or ASIAuthenticationDialog subclass.

Presenting credentials before the server asks for them

IMPORTANT
Behaviour for this feature has changed in v1.8.1 for requests using Basic authentication, and you may need to update your code.



ASIHTTPRequest can present credentials to the server (if it has credentials to use) when it first makes a request, rather than waiting for the server to ask for credentials. This can result in better performance for applications using authentication, since it avoids an extra request.

To trigger this behaviour for requests using Basic authentication, you should manually set the request’s authenticationScheme to use Basic:

[request setAuthenticationScheme:(NSString *)kCFHTTPAuthenticationSchemeBasic];

For other authentication schemes, credentials can be presented before the server asks for them, but only after another request has successfully authenticated with the server.

You may wish to disable this feature if:

  • Your application may use multiple sets of credentials to talk to the same server at once
  • Security is paramount for your application. Using this feature is inherently less secure, since credentials are sent before you have a chance to validate that you are connecting to the server you thought you were connecting to.

To disable this feature, use this code:

[request setShouldPresentCredentialsBeforeChallenge:NO];

Cookies

Persistent cookies

ASIHTTPRequest allows you to use the global store shared by all Mac OS X applications that use the CFNetwork or NSURLRequest APIs. If useCookiePersistence is on (it is by default), cookies will be stored in the shared NSHTTPCookieStorage container, and reused on other requests automatically. It’s worth noting that ASIHTTPRequest might present cookies created in other applications if they are valid for a particular request.

You can clear all cookies created during a session like so:

[ASIHTTPRequest setSessionCookies:nil];

In this case, ‘session cookies’ refers to ALL cookies created during a session, rather cookies with no expiry date (often referred to as session cookies) that are removed when the application quits.

Alternatively, the convenience class method clearSession will clear all cookies created during the session, along with any cached authentication data.

Handling cookies yourself

If you prefer, you can turn off useCookiePersistence, and manage the set of cookies for a particular request manually:

//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:[NSDate dateWithTimeIntervalSinceNow:*] 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:[NSMutableArray arrayWithObject:cookie]];
[request startSynchronous];
 
//Should be: I have 'Test Value' as the value of 'ASIHTTPRequestTestCookie'
NSLog(@"%@",[request responseString]);
 

ASIHTTPRequest学习(一)的更多相关文章

  1. ASIHTTPRequest学习(三)

    刚刚开始学习ASIHttpRequest,今天通过自己写的一个小demo分享一下学习心得. 首先,要想在ios项目中使用ASIHttpRequest,必须添加下列框架和类库: ASIHttpReque ...

  2. ASIHTTPRequest学习笔记

    1.creating requestsrequest分为同步和异步两种.不同之处在于开始request的函数:[request startSynchronous];[request startAsyn ...

  3. ios 的ASIHTTPRequest学习

    发起一个同步请求 同步意为着线程阻塞,在主线程中使用此方法会使应用Hang住而不响应任何用户事件.所以,在应用程序设计时,大多被用在专门的子线程增加用户体验,或用异步请求代替(下面会讲到). - (I ...

  4. ASIHTTPRequest学习(四)

    如果是IOS5的版本,可能集成过程中会遇到一些问题,我也找到了一些解决方案,比如,集成完后可能会遇到编译提示找不到"libxml/HTMLparser.h",解决这个问题可以参考这 ...

  5. ASIHTTPRequest学习(二)

    Handling compressed responses, and compressing request bodies Using gzip to handle compressed respon ...

  6. IOS学习笔记25—HTTP操作之ASIHTTPRequest

    IOS学习笔记25—HTTP操作之ASIHTTPRequest 分类: iOS2012-08-12 10:04 7734人阅读 评论(3) 收藏 举报 iosios5网络wrapper框架新浪微博 A ...

  7. IOS学习笔记25—HTTP操作之ASIHTTPRequest(一)

    ASIHTTPRequest是一个第三方开源项目,在现在的IOS应用中多使用到这个开源类库来提供网络操作,相比于SDK提供的网络操作类库,ASIHTTPRequest使用上更加方便.效率更高,同时功能 ...

  8. IOS开发---菜鸟学习之路--(十二)-利用ASIHTTPRequest进行异步获取数据

    想要实现异步获取的话我这边了解过来有两个非常简单的方式 一个是利用ASIHTTPRequest来实现异步获取数据 另一个则是利用MBProgressHUD来实现异步获取数据 本章就先来讲解如何利用AS ...

  9. ASIHTTPRequest简单学习

    ASIHTTPRequest框架是优秀的第三方Objective-C的HTTP框架,支持Mac OS X和iOS下的HTTP开发. 一.ASIHTTPRequest框架的安装和配置 (1)首先要在项目 ...

随机推荐

  1. Codeforces Round #329(Div2)

    CodeForces 593A 题意:n个字符串,选一些字符串,在这些字符串中使得不同字母最多有两个,求满足这个条件可选得的最多字母个数. 思路:用c[i][j]统计文章中只有i,j对应两个字母出现的 ...

  2. nginx 匹配路由分发php和golang

    大概这么个形式,可以走通 server { listen ; server_name localhost; root "E:/wwwroot180/public"; # 匹配指定路 ...

  3. PHP字符串基本操作函数

    常用函数: trim():去除字符串的空格及传入的参数 strlen():获取字符串长度 substr():按照两个参数截取字符串 str_replace():字符串替换 str_split():将字 ...

  4. Extjs 4 小记

    ////////////////////////////////////---Ajax 等待提示消息---/////////////////////////////////////////////// ...

  5. Java常用实体类

    System类 访问系统属性 - 遍历 package org.zln.usefulclass.system; import java.util.Properties; /** * Created b ...

  6. 【bzoj3747】[POI2015]Kinoman 线段树区间合并

    题目描述 一个长度为n的序列,每个数为1~m之一.求一段连续子序列,使得其中之出现过一次的数对应的价值之和最大. 输入 第一行两个整数n,m(1<=m<=n<=1000000). 第 ...

  7. idea创建maven项目需要注意的问题

    idea创建maven项目之后,我从deployment中看到报部署错误的问题,下图是解决问题的办法如下图所示:

  8. php 内核变量 引用计数器写时复制

    写时复制,是一个解决内存复用的方法,就是你在php语言层,如$d=$c=$b=$a='value';把$a赋给另一个或多个变量,这时这个变量都只占用一个内存块,当其中一个变量值改变时,才会开辟另一个内 ...

  9. [LeetCode] Search for a Range 二分搜索

    Given a sorted array of integers, find the starting and ending position of a given target value. You ...

  10. error LNK2001: unresolved external symbol "int g_cTemplates" (?g_cTemplates@@3HA)(转)

    原文转自:http://blog.sina.com.cn/s/blog_639a2ad70101kpen.html 编译directshow若干问题的解决 1.安装好windows sdk,进入dir ...