iOS开源项目:asi-http-request
使用CFNetwork实现的http库,能同时在iphone和macos下使用:http://allseeing-i.com/ASIHTTPRequest/
他提供以下功能:
- 向服务器发送或者从服务器获取数据的接口
- 下载数据,可以保存到内存里,或者保存的磁盘的文件里。
- 以POST的方式提交本地文件,和HTML文件输入机制兼容。
- 以流的方式把磁盘里的文件发送的服务器
- 断点续传
- 方便的访问request 和 response HTTP headers
- 进度代理,利用NSProgressIndicators and UIProgressViews显示上传和下载的进度
- 自动管理上传和下载的进度。
- 支持Cookie
-
Requests可在后台运行
-
response data 和 request bodies支持GZIP
-
ASIWebPageRequest-下载整个网页。
- 支持Amazon S3
- 支持Rackspace Cloud Files
- 支持客户端证书
- 支持长连接
- 支持同步和异步请求
- 可以通过代理获取request状态的变化。
1、使用方法
1.1同步请求:
- (IBAction)grabURL:(id)sender { 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]; } }
a, 用requestWithURL快捷方法获取ASIHTTPRequest的一个实例
b, startSynchronous 方法启动同步访问,
c, 由于是同步请求,没有基于事件的回调方法,所以从request的error属性获取错误信息。
d, responseString,为请求的返回NSString信息。
1.2异步请求:
- (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]; }
a,与上面不同的地方是指定了一个 “delegate”,并用startAsynchronous来启动网络请求。
b,在这里实现了两个delegate的方法,当数据请求成功时会调用requestFinished,请求失败时(如网络问题或服务器内部错误)会调用requestFailed。
1.3队列请求:
提供了一个对异步请求更加精准丰富的控制。适用于多个请求按顺序执行。
if (!networkQueue) { networkQueue = [[ASINetworkQueue alloc] init]; } failed = NO; [networkQueue reset]; [networkQueue setDownloadProgressDelegate:progressIndicator]; [networkQueue setRequestDidFinishSelector:@selector(imageFetchComplete:)]; [networkQueue setRequestDidFailSelector:@selector(imageFetchFailed:)]; [networkQueue setShowAccurateProgress:[accurateProgress isOn]]; [networkQueue setDelegate:self]; ASIHTTPRequest *request; request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/images/small-image.jpg"]]; [request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"1.png"]]; [request setDownloadProgressDelegate:imageProgressIndicator1]; [request setUserInfo:[NSDictionary dictionaryWithObject:@"request1" forKey:@"name"]]; [networkQueue addOperation:request]; request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/images/medium-image.jpg"]] autorelease]; [request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"2.png"]]; [request setDownloadProgressDelegate:imageProgressIndicator2]; [request setUserInfo:[NSDictionary dictionaryWithObject:@"request2" forKey:@"name"]]; [networkQueue addOperation:request]; request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/images/large-image.jpg"]] autorelease]; [request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:@"3.png"]]; [request setDownloadProgressDelegate:imageProgressIndicator3]; [request setUserInfo:[NSDictionary dictionaryWithObject:@"request3" forKey:@"name"]]; [networkQueue addOperation:request]; [networkQueue go];
1.4使用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]; }
1.4取消异步请求:
首先,同步请求是不能取消的。
其次,不管是队列请求,还是简单的异步请求,全部调用[ request cancel ]来取消请求。
1.5向服务器上传数据:
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"]; [request addData:imageData withFileName:@"george.jpg" andContentType:@"image/jpeg" forKey:@"photos"]; //如果要发送自定义数据: 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"];
1.6下载文件:
通过设置request的setDownloadDestinationPath,可以设置下载文件用的下载目标目录。
首先,下载过程文件会保存在temporaryFileDownloadPath目录下。如果下载完成会做以下事情:
1,如果数据是压缩的,进行解压,并把文件放在downloadDestinationPath目录中,临时文件被删除
2,如果下载失败,临时文件被直接移到downloadDestinationPath目录,并替换同名文件。
如果你想获取下载中的所有数据,可以实现delegate中的request:didReceiveData:方法。但如果你实现了这个方法,request在下载完后,request并不把文件放在downloadDestinationPath中,需要手工处理。
1.7获取请求进度:
有两个回调方法可以获取请求进度,
1,downloadProgressDelegate,可以获取下载进度
2,uploadProgressDelegate,可以获取上传进度
1.8cookie:
如果Cookie存在的话,会把这些信息放在NSHTTPCookieStorage容器中共享,并供下次使用。
你可以用[ ASIHTTPRequest setSessionCookies:nil ] ; 清空所有Cookies。
当然,你也可以取消默认的Cookie策略,而使自定义的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: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:[NSMutableArray arrayWithObject:cookie]]; [request startSynchronous]; //Should be: I have ’Test Value’ as the value of ’ASIHTTPRequestTestCookie’ NSLog(@“%@”,[request responseString]);
1.9断点续传:
[ request setAllowResumeForFileDownloads:YES ];
[ request setDownloadDestinationPath:downloadPath ];
2.0其他:
是否有网络请求:
[ ASIHTTPRequest isNetworkInUse ]
是否显示网络请求信息在status bar上:
[ ASIHTTPRequest setShouldUpdateNetworkActivityIndicator:NO ];
设置请求超时时,设置重试的次数:
[ request setNumberOfTimesToRetryOnTimeout:2 ];
后台执行:
[ request setShouldContinueWhenAppEntersBackground:YES ];
参考:
1、http://wiki.magiche.net/pages/viewpage.action?pageId=2064410
2、http://sev7n.net/index.php/615.html
3、http://allseeing-i.com/ASIHTTPRequest/How-to-use
2、源码解读:
ASIHTTPRequest是NSOperation的子类。
发起同步请求的过程是:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
- (void)startSynchronous { #if DEBUG_REQUEST_STATUS || DEBUG_THROTTLING NSLog(@"Starting synchronous request %@",self); #endif [self setSynchronous:YES]; [self setRunLoopMode:ASIHTTPRequestRunLoopMode]; [self setInProgress:YES]; if (![self isCancelled] && ![self complete]) { [self main]; while (!complete) { [[NSRunLoop currentRunLoop] runMode:[self runLoopMode] beforeDate:[NSDate distantFuture]]; } } [self setInProgress:NO]; }
在重载的main方法中,建立了一个HTTP request:
request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, (CFStringRef)[self requestMethod], (CFURLRef)[self url], [self useHTTPVersionOne] ? kCFHTTPVersion1_0 : kCFHTTPVersion1_1);
kCFAllocatorDefault指定了将使用默认的系统内存管理器创建消息引用,requestMethod指定了消息请求的执行方式,(CFURLRef)[self url]指定将要请求的远程地址,kCFHTTPVersion1_1指定HTTP请求的版本为1.1。CFHTTPMessageCreateRequest函数的返回值就是消息对象的引用。
然后,在startRequest方法中,通过CFReadStreamOpen发送请求
// Start the HTTP connection CFStreamClientContext ctxt = {0, self, NULL, NULL, NULL}; if (CFReadStreamSetClient((CFReadStreamRef)[self readStream], kNetworkEvents, ReadStreamClientCallBack, &ctxt)) { if (CFReadStreamOpen((CFReadStreamRef)[self readStream])) { streamSuccessfullyOpened = YES; } }