创建和执行Request
一、创建一个同步请求
- 这是ASIHttpRequest最简单的使用方式。
- 通过发送startSynchronous消息在同一线程中执行请求,当请求完成时(不管请求成功还是失败)返回控制。
- 通过检查error属性来检测错误
- 同步请求会阻塞主线程的执行,这导致用户界面不响应用户操作,任何动画都会停止渲染。
- 如果请求string数据,则使用responseString方法;如果请求二进制数据(图片,音乐,视频等),则使用responseData方法;如果下载文件,则使用downloadDestinationPath属性来指定路径
示例代码
- (IBAction)grabURL:(id)sender //一般执行请求时都是点击了某个Button(最为常见),所以此处使用IBAction
{
NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString]; //同步请求中,将startSynchronous和error写在了一个方法里面
}
}
二、创建一个异步请求
跟上面的基本原理是相同的,只是请求在后台执行,不会阻塞主进程的执行
示例代码
- (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
{
NSString *responseString = [request responseString]; //获取string数据(如用户名和密码)
NSData *responseData = [request responseData]; //获取二进制数据(图片、视频、音乐)
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
NSError *error = [request error]; //返回错误信息
}
三、使用blocks
- 在平台支持情况下,ASIHTTPRequest1.8以上支持block。
- 声明request时要使用__block修饰符,这是为了告诉block不要retain request,以免出现retain循环,因为request是会retain 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];
}
四、使用队列
- 通过使用NSOperationQueue或者 ASINetworkQueue,我们可以在异步请求中创建更多的控制进程。
- 当使用队列时,在同一时间只能运行确定数目的请求。
- 他定义了maxConcurrentOperationCount属性,表示同一时间的最大并发连接数,如果超过了这个数值,请求必须等待其他请求完成后才会开始执行
- 如果需要对队列里面的每个request进行区分,那么可以设定request的userInfo属性,它是个NSDictionary,或者更简单的方法是设定每个request的tag属性,这两个属性都不会被发送到服务器。
- 不要使用request的URL来区分每个request,因为URL可能会改变(例如重定向),如果需要使用request的URL,使用[request originalURL],这个将永远返回第一个url。
示例代码
- (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:)]; //注意此处使用了@selector,下面有详解
[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];
}
五、关于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。要禁用这个特性,设置 [queue setShouldCancelAllRequestsOnFailure:NO]。
- ASINetworkQueues只可以执行ASIHTTPRequest操作,而不可以用于通用操作。试图加入一个不是ASIHTTPRequest的NSOperation将会导致发生错误。
向一个已经开始进行的ASINetworkQueue 加入request会怎样?
如果你使用ASINetworkQueue来跟踪若干request的进度,只有当新的request开始执行时,总进度才会进行自适应调整(向后移动)。ASINetworkQueue不会为队列开始后才加入的request进行HEAD请求,所以如果你一次向一个正在执行的队列加入很多request,那么总进度不会立即被更新。
如果队列已经开始了,不需要再次调用[queue go]。
如果你使用ASINetworkQueue来跟踪若干request的进度,只有当新的request开始执行时,总进度才会进行自适应调整(向后移动)。ASINetworkQueue不会为队列开始后才加入的request进行HEAD请求,所以如果你一次向一个正在执行的队列加入很多request,那么总进度不会立即被更新。
如果队列已经开始了,不需要再次调用[queue go]。
六、取消异步请求
- 取消一个异步请求(无论request是由[request startAsynchronous]开始的还是从你创建的队列中开始的),使用[request cancel]即可。注意同步请求不可以被取消。
- 如果你取消了一个request,那么这个request将会被视为请求失败,并且request的代理或者队列的代理的失败代理函数将被调用。
- 如果你不想让代理函数被调用,那么将delegate设置为nil,或者使用clearDelegatesAndCancel方法来取消request。clearDelegatesAndCancel 将会首先清除所有的代理和block。
- 当使用ASINetworkQueue时,如果取消了队列中的一个request,那么队列中其他所有request都会被取消,可以设置shouldCancelAllRequestsOnFailure的值为NO来避免这个现象。
示例代码
[request cancel] // 取消一个异步请求
[request clearDelegatesAndCancel]; //取消一个异步请求,首先要清除所有的delegates和blocks
[queue setShouldCancelAllRequestsOnFailure:NO]; //当队列中的一个请求失败或者取消,其他的请求可以继续运行
[queue cancelAllOperations]; // 取消队列中所有的请求
七、发送数据
1.设定request头
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request addRequestHeader:@"Referer" value:@"http://allseeing-i.com/"]; //添加请求头
2.使用ASIFormDataRequest POST表单
- 要想使用兼容的方式POST一个表单,必须使用ASIFormDataRequest这个类
- 通常数据是以’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"];
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"];
3.你可以通过使用add这个非正式的API来为同一个参数发送多个值
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request addPostValue:@"Ben" forKey:@"names"]; //以前使用的是setPostValue,此处使用的是addPostValue,这个要注意
[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"];
// Add a POST variable to the request
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key;
// Set a POST variable for this request, clearing any others with the same key
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key;
// Add the contents of a local file to the request
- (void)addFile:(NSString *)filePath forKey:(NSString *)key;
// Same as above, but you can specify the content-type and file name
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
// Add the contents of a local file to the request, clearing any others with the same key
- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
// Same as above, but you can specify the content-type and file name
- (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
// Add the contents of an NSData object to the request
- (void)addData:(NSData *)data forKey:(NSString *)key;
// Same as above, but you can specify the content-type and file name
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
// Add the contents of an NSData object to the request, clearing any others with the same key
- (void)setData:(NSData *)data forKey:(NSString *)key;
// Same as above, but you can specify the content-type and file name
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
set方法会清除同一个key的其他值,add方法只是在原来不变的情况下,给key增加更多的值
4.PUT请求、自定义POST请求
如果你想发送PUT请求,或者你想自定义POST请求,使用
appendPostData: 或者
appendPostDataFromFile:这两个方法
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request appendPostData:[@"This is my data" dataUsingEncoding:NSUTF8StringEncoding]];
//当你使用appendPostData: / appendPostDataFromFile: / setPostBody:等方法时,默认的是POST请求方式
[request setRequestMethod:@"PUT"]; //改变请求方式