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;
        }
    }

 

 

posted @ 2013-06-20 15:47  shangdahao  阅读(1261)  评论(0编辑  收藏  举报