zoukankan      html  css  js  c++  java
  • 第三方苹果开发库之ASIHTTPRequest(翻译版)

     

    本文转载至 http://blog.csdn.net/chenzhiqin20/article/details/8474844 

    转载表明出处:http://www.cnblogs.com/daguo/archive/2012/08/03/2622090.html

    英文原文来自: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来保存文件到本地):

    1. - (IBAction)grabURL:(id)sender  
    2. {  
    3.   NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];  
    4.   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    5.   [request startSynchronous];  
    6.   NSError *error = [request error];  
    7.   if (!error) {  
    8.     NSString *response = [request responseString];  
    9.   }  
    10. }  

    同步请求会阻塞主线程的执行,这导致用户界面不响应用户操作,任何动画都会停止渲染。

    异步请求

    下面是最简单的异步请求方法,这个request会在全局的NSOperationQueue中执行,若要进行更复杂的操作,我们需要自己创建NSOperationQueue或者ASINetworkQueue,后面会讲到。

    1. - (IBAction)grabURLInBackground:(id)sender  
    2. {  
    3.    NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];  
    4.    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    5.    [request setDelegate:self];  
    6.    [request startAsynchronous];  
    7. }  
    8.   
    9. - (void)requestFinished:(ASIHTTPRequest *)request  
    10. {  
    11.    // Use when fetching text data  
    12.    NSString *responseString = [request responseString];  
    13.   
    14.    // Use when fetching binary data  
    15.    NSData *responseData = [request responseData];  
    16. }  
    17.   
    18. - (void)requestFailed:(ASIHTTPRequest *)request  
    19. {  
    20.    NSError *error = [request error];  
    21. }  

     

    使用block

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

    1. - (IBAction)grabURLInBackground:(id)sender  
    2. {  
    3.    NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];  
    4.    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    5.    [request setCompletionBlock:^{  
    6.       // Use when fetching text data  
    7.       NSString *responseString = [request responseString];  
    8.   
    9.       // Use when fetching binary data  
    10.       NSData *responseData = [request responseData];  
    11.    }];  
    12.    [request setFailedBlock:^{  
    13.       NSError *error = [request error];  
    14.    }];  
    15.    [request startAsynchronous];  
    16. }  

    注意,声明request时要使用__block修饰符,这是为了告诉block不要retain request,以免出现retain循环,因为request是会retain block的。

    使用队列

    创建NSOperationQueue或者ASINetworkQueue队列,我们还可以设定最大并发连接数:maxConcurrentOperationCount 

    1. - (IBAction)grabURLInTheBackground:(id)sender  
    2. {  
    3.    if (![self queue]) {  
    4.       [self setQueue:[[[NSOperationQueue alloc] init] autorelease]];  
    5.       [self queue].maxConcurrentOperationCount = 4;  
    6.    }  
    7.   
    8.    NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];  
    9.    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    10.    [request setDelegate:self];  
    11.    [request setDidFinishSelector:@selector(requestDone:)];  
    12.    [request setDidFailSelector:@selector(requestWentWrong:)];  
    13.    [[self queue] addOperation:request]; //queue is an NSOperationQueue  
    14. }  
    15.   
    16. - (void)requestDone:(ASIHTTPRequest *)request  
    17. {  
    18.    NSString *response = [request responseString];  
    19. }  
    20.   
    21. - (void)requestWentWrong:(ASIHTTPRequest *)request  
    22. {  
    23.    NSError *error = [request error];  
    24. }  

    如果不设定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,因为你已经不再关心它们的返回情况了。如此做:

    1. // 代理类的<span style="margin:0px; padding:0px">dealloc</span>函数  
    2. <span style="margin:0px; padding:0px">- (void)dealloc  
    3. {  
    4.    [request clearDelegatesAndCancel];  
    5.    [request release];  
    6.    ...  
    7.    [super dealloc];  
    8. }<br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"></span>  

    ASIHttpRequest-发送数据

     

     

    发送数据

    设定request头

    1. <span style="margin:0px; padding:0px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request addRequestHeader:@"Referer" value:@"http://www.dreamingwish.com/"];</span>  

    使用ASIFormDataRequest POST表单

    通常数据是以’application/x-www-form-urlencoded’格式发送的,如果上传了二进制数据或者文件,那么格式将自动变为‘multipart/form-data’ 

    文件中的数据是需要时才从磁盘加载,所以只要web server能处理,那么上传大文件是没有问题的。

    1. <span style="margin:0px; padding:0px">ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];  
    2. [request setPostValue:@"Ben" forKey:@"first_name"];  
    3. [request setPostValue:@"Copsey" forKey:@"last_name"];  
    4. [request setFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photo"];</span>  

    数据的mime头是自动判定的,但是如果你想自定义mime头,那么这样:

    1. <span style="margin:0px; padding:0px">ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];  
    2.   
    3. // Upload a file on disk  
    4. [request setFile:@"/Users/ben/Desktop/ben.jpg" withFileName:@"myphoto.jpg" andContentType:@"image/jpeg"  
    5. forKey:@"photo"];  
    6.   
    7. // Upload an NSData instance  
    8. [request setData:imageData withFileName:@"myphoto.jpg" andContentType:@"image/jpeg" forKey:@"photo"];</span>  

    你可以使用addPostValue方法来发送相同name的多个数据(梦维:服务端会以数组方式呈现):

    1. <span style="margin:0px; padding:0px">ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];  
    2. [request addPostValue:@"Ben" forKey:@"names"];  
    3. [request addPostValue:@"George" forKey:@"names"];  
    4. [request addFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photos"];  
    5. [request addData:imageData withFileName:@"george.jpg" andContentType:@"image/jpeg" forKey:@"photos"];</span>  

    PUT请求、自定义POST请求

    如果你想发送PUT请求,或者你想自定义POST请求,使用appendPostData: 或者 appendPostDataFromFile:

    1. <span style="margin:0px; padding:0px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request appendPostData:[@"This is my data" dataUsingEncoding:NSUTF8StringEncoding]];  
    3. // Default becomes POST when you use appendPostData: / appendPostDataFromFile: / setPostBody:  
    4. [request setRequestMethod:@"PUT"];</span>  
    1.   

    ASIHTTPRequest-下载数据

    1.   

    将服务器响应数据直接下载到文件

    如果你请求的资源很大,你可以直接将数据下载到文件中来节省内存。此时,ASIHTTPRequest将不会一次将返回数据全部保持在内存中。

    1. <span style="margin:0px; padding:0px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request setDownloadDestinationPath:@"/Users/ben/Desktop/my_file.txt"];</span>  

    当我们把数据下载到downloadDestinationPath时,数据将首先被存在临时文件中。此时文件的路径名存储在temporaryFileDownloadPath中(梦维:如果不设置这个值,会自动生成一个文件名,在模拟器中,文件被创建在$TMPDIR中)。当request完成时,会发生下面两件事之一:

    • 如果数据是被压缩过(gzip)的,那么这个压缩过的文件将被解压到downloadDestinationPath,临时文件会被删除。
    • 如果数据未被压缩,那么这个文件将被移动到downloadDestinationPath,冲突解决方式是:覆盖已存在的文件。

    注意,如果服务器响应数据为空,那么文件是不会被创建的。如果你的返回数据可能为空,那么你应该先检查下载文件是否存在,再对文件进行操作。

    处理收到的服务器响应数据

    如果你想处理服务器响应的数据(例如,你想使用流解析器对正在下载的数据流进行处理),你应该实现代理函数 request:didReceiveData:。注意如果你这么做了,ASIHTTPRequest将不会填充responseData到内存,也不会将数据写入文件(downloadDestinationPath )——你必须自己搞定这两件事(之一)。 

    获取HTTP状态码

    ASIHTTPRequest并不对HTTP状态码做任何处理(除了重定向和授权状态码,下面会介绍到),所以你必须自己检查状态值并正确处理。

    1. <span style="margin:0px; padding:0px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request startSynchronous];  
    3. int statusCode = [request responseStatusCode];  
    4. NSString *statusMessage = [request responseStatusMessage];</span>  

     

    读取响应头

    1. <span style="margin:0px; padding:0px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request startSynchronous];  
    3. NSString *poweredBy = [[request responseHeaders] objectForKey:@"X-Powered-By"];  
    4. NSString *contentType = [[request responseHeaders] objectForKey:@"Content-Type"];</span>  

    处理文本编码

    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。

    1. <span style="margin:0px; padding:0px"> </span>  

    ASIHTTPRequest-进度追踪

    1.   
     

    每个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.

    1. <span style="margin:0px; padding:0px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request setDownloadProgressDelegate:myProgressIndicator];  
    3. [request startSynchronous];  
    4. NSLog(@"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);</span>  

     

    追踪一系列request的下载进度

    在这个例子中, myProgressIndicator 是个 UIProgressView, myQueue是个 ASINetworkQueue.

    1. <span style="margin:0px; padding:0px">- (void)fetchThisURLFiveTimes:(NSURL *)url  
    2. {  
    3.    [myQueue cancelAllOperations];  
    4.    [myQueue setDownloadProgressDelegate:myProgressIndicator];  
    5.    [myQueue setDelegate:self];  
    6.    [myQueue setRequestDidFinishSelector:@selector(queueComplete:)];  
    7.    int i;  
    8.    for (i=0; i<5; i++) {  
    9.       ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    10.       [myQueue addOperation:request];  
    11.    }  
    12.    [myQueue go];  
    13. }  
    14.    
    15. - (void)queueComplete:(ASINetworkQueue *)queue  
    16. {  
    17.    NSLog(@"Value: %f", [myProgressIndicator progress]);  
    18. }</span>  

    这个例子中,我们已经为ASINetworkQueues调用过[myQueue go]了。

    追踪单个request的上传进度

    在这个例子中, myProgressIndicator 是个 UIProgressView。

    1. <span style="margin:0px; padding:0px">ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];  
    2. [request setPostValue:@"Ben" forKey:@"first_name"];  
    3. [request setPostValue:@"Copsey" forKey:@"last_name"];  
    4. [request setUploadProgressDelegate:myProgressIndicator];  
    5. [request startSynchronous];  
    6. NSLog(@"Value: %f",[myProgressIndicator progress]);</span>  

    追踪一系列request的上传进度

    这个例子中, myProgressIndicator是个 NSProgressIndicator, myQueue是个ASINetworkQueue.

    1. <span style="margin:0px; padding:0px">- (void)uploadSomethingFiveTimes:(NSURL *)url  
    2. {  
    3.    [myQueue cancelAllOperations];  
    4.    [myQueue setUploadProgressDelegate:myProgressIndicator];  
    5.    [myQueue setDelegate:self];  
    6.    [myQueue setRequestDidFinishSelector:@selector(queueComplete:)];  
    7.    int i;  
    8.    for (i=0; i<5; i++) {  
    9.       ASIHTTPRequest *request = [ASIFormDataRequest requestWithURL:url];  
    10.       [request setPostBody:[@"Some data" dataUsingEncoding:NSUTF8StringEncoding]];  
    11.       [myQueue addOperation:request];  
    12.    }  
    13.    [myQueue go];  
    14. }  
    15.    
    16. - (void)queueComplete:(ASINetworkQueue *)queue  
    17. {  
    18.    NSLog(@"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);  
    19. }</span>  

    精确进度条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指定要使用的用户名和密码

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];</span>  

    为request指定要使用的用户名和密码

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    3. [request setUsername:@"username"];  
    4. [request setPassword:@"password"];</span>  

    将凭据存储到keychain

    如果打开了keychainPersistence,所有提供的可用的用户名和密码将被存储到keychain中,以后的request将会重用这些用户名密码,即使你关闭程序后重新打开也不影响。

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    3. [request setUseKeychainPersistence:YES];  
    4. [request setUsername:@"username"];  
    5. [request setPassword:@"password"];</span>  

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

    将凭据存储到session中

    如果打开了useSessionPersistence(默认即是如此),ASIHTTPRequest会把凭据存储到内存中,后来的request将会重用这些凭据。

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    3. [request setUsername:@"username"];  
    4. [request setPassword:@"password"];  
    5. [request setUseSessionPersistence:YES]; //这一项是默认的,所以并不必要  
    6.   
    7. //将会重用我们的 username 和 password  
    8. request = [ASIHTTPRequest requestWithURL:url];</span>  

    NTLM授权

    要使用NTLM授权的Windows服务器,你还需要指定你要进行授权域。

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    3. [request setUsername:@"username"];  
    4. [request setPassword:@"password"];  
    5. [request setDomain:@"my-domain"];</span>  

    使用代理来提供凭据

    你不一定非要提前指定授权凭据,你还可以让每个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:

    1. <span style="margin:0px; padding:0px">[request setAuthenticationScheme:(NSString *)kCFHTTPAuthenticationSchemeBasic];</span>  

    对于其他授权方案,凭据也可以在服务器要求之前被发送,但是仅当有另一个request成功授权之后才行。

    在以下情况下,你也许想要禁用这个特性:

    • 你的程序可能会一次使用一系列凭据来与服务器对话
    • 安全性对于你的程序来说非常重要。使用这个特性是相对不安全的,因为你不能在凭据被发送前验证你是否连接到了正确的服务器。

    要禁用这个特性,这样做:

    1. <span style="margin:0px; padding:0px">[request setShouldPresentCredentialsBeforeChallenge:NO];<br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"></span>  

    ASIHTTPRequest-HTTP授权-流程图

    1. <span style="margin:0px; padding:0px"><span style="margin:0px; padding:0px; font-family:verdana,Arial,Helvetica,sans-serif"><span style="margin:0px; padding:0px"><img src="http://www.dreamingwish.com/wp-content/uploads/2011/10/asihttprequest-auth.png" alt="" width="800" height="1223" style="margin:0px; padding:0px; border:0px; float:left"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"></span></span></span>  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  
    1.   

    ASIHTTPRequest-Cookie的使用

     

    持久化cookie

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

    如果设置useCookiePersistence为YES(默认值),cookie会被存储在共享的 NSHTTPCookieStorage 容器中,并且会自动被其他request重用。值得一提的是,ASIHTTPRequest会向服务器发送其他程序创建的cookie(如果这些cookie对特定request有效的话)。

    你可以清空session期间创建的所有cookie:

    1. <span style="margin:0px; padding:0px">[ASIHTTPRequest setSessionCookies:nil];</span>  

    这里的‘session cookies’指的是一个session中创建的所有cookie,而非没有过期时间的cookie(即通常所指的会话cookie,这种cookie会在程序结束时被清除)。

    另外,有个方便的函数 clearSession可以清除session期间产生的所有的cookie和缓存的授权数据。 

    自己处理cookie

    如果你愿意,你大可以关闭useCookiePersistence,自己来管理某个request的一系列cookie:

    1. <span style="margin:0px; padding:0px">//创建一个cookie  
    2. NSDictionary *properties = [[[NSMutableDictionary alloc] init] autorelease];  
    3. [properties setValue:[@"Test Value" encodedCookieValue] forKey:NSHTTPCookieValue];  
    4. [properties setValue:@"ASIHTTPRequestTestCookie" forKey:NSHTTPCookieName];  
    5. [properties setValue:@".dreamingwish.com" forKey:NSHTTPCookieDomain];  
    6. [properties setValue:[NSDate dateWithTimeIntervalSinceNow:60*60] forKey:NSHTTPCookieExpires];  
    7. [properties setValue:@"/asi-http-request/tests" forKey:NSHTTPCookiePath];  
    8. NSHTTPCookie *cookie = [[[NSHTTPCookie alloc] initWithProperties:properties] autorelease];  
    9.   
    10. //这个url会返回名为'ASIHTTPRequestTestCookie'的cookie的值  
    11. url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    12. request = [ASIHTTPRequest requestWithURL:url];  
    13. [request setUseCookiePersistence:NO];  
    14. [request setRequestCookies:[NSMutableArray arrayWithObject:cookie]];  
    15. [request startSynchronous];  
    16.   
    17. //将会打印: I have 'Test Value' as the value of 'ASIHTTPRequestTestCookie'  
    18. NSLog(@"%@",[request responseString]);</span>  
    1.   

    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

    1. <span style="margin:0px; padding:0px">- (IBAction)grabURL:(id)sender  
    2. {  
    3.   NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];  
    4.   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    5.   // 默认为YES, 你可以设定它为NO来禁用gzip压缩  
    6.   [request setAllowCompressedResponse:YES];  
    7.   [request startSynchronous];  
    8.   BOOLBOOL *dataWasCompressed = [request isResponseCompressed]; // 响应是否被gzip压缩过?  
    9.   NSData *compressedResponse = [request rawResponseData]; // 压缩的数据  
    10.   NSData *uncompressedData = [request responseData]; // 解压缩后的数据  
    11.   NSString *response = [request responseString]; // 解压缩后的字符串  
    12. }</span>  

    当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)进行压缩,你会发现压缩后的数据比原数据更大。(梦维:因为压缩包都有头信息)

    1.   

    ASIHTTPRequest-断点续传(下载)

     

    从0.94版本开始,ASIHTTPRequest可以恢复中断的下载

    1. <span style="margin:0px; padding:0px">- (IBAction)resumeInterruptedDownload:(id)sender  
    2. {  
    3.   NSURL *url = [NSURL URLWithString:  
    4.     @"http://www.dreamingwish.com/wp-content/uploads/2011/10/asihttprequest-auth.png"];  
    5.   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    6.    
    7.   NSString *downloadPath = @"/Users/ben/Desktop/asi.png";  
    8.    
    9.   //当request完成时,整个文件会被移动到这里  
    10.   [request setDownloadDestinationPath:downloadPath];  
    11.    
    12.   //这个文件已经被下载了一部分  
    13.   [request setTemporaryFileDownloadPath:@"/Users/ben/Desktop/asi.png.download"];  
    14.   [request setAllowResumeForFileDownloads:YES];  
    15.   [request startSynchronous];  
    16.    
    17.   //整个文件将会在这里  
    18.   NSString *theContent = [NSString stringWithContentsOfFile:downloadPath];  
    19. }</span>  

    这个特性只对下载数据到文件中有效,你必须为一下情况的request设置allowResumeForFileDownloads 为YES:

    • 任何你希望将来可以断点续传的下载(否则,ASIHTTPRequest会在取消或者释放内存时将临时文件删除)
    • 任何你要进行断点续传的下载

    另外,你必须自己设置一个临时下载路径(setTemporaryFileDownloadPath),这个路径是未完成的数据的路径。新的数据将会被添加到这个文件,当下载完成时,这个文件将被移动到downloadDestinationPath 。

    断点续传的工作原理是读取temporaryFileDownloadPath的文件的大小,并使用Range: bytes=x HTTP头来请求剩余的文件内容。

    ASIHTTPRequest并不检测是否存在Accept-Ranges头(因为额外的HEAD头请求会消耗额外的资源),所以只有确定服务器支持断点续传下载时,再使用这个特性。

    1. <br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px">  

    ASIHTTPRequest-直接读取磁盘数据流的请求体

     

    从0.96版本开始,ASIHTTPRequest可以使用磁盘上的数据来作为请求体。这意味着不需要将文件完全读入内存中,这就避免的当使用大文件时的严重内存消耗。

    使用这个特性的方法有好几种:

    ASIFormDataRequests

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    2. ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];  
    3. [request setPostValue:@"foo" forKey:@"post_var"];  
    4. [request setFile:@"/Users/ben/Desktop/bigfile.txt" forKey:@"file"];  
    5. [request startSynchronous];</span>  

    当使用setFile:forKey:时,ASIFormDataRequests 自动使用这个特性。request将会创建一个包含整个post体的临时文件。文件会一点一点写入post体。这样的request是由CFReadStreamCreateForStreamedHTTPRequest创建的,它使用文件读取流来作为资源。

    普通ASIHTTPRequest

    如果你明白自己的request体会很大,那么为这个request设置流式读取模式。

    1. <span style="margin:0px; padding:0px">[request setShouldStreamPostDataFromDisk:YES];</span>  

    下面的例子中,我们将一个NSData对象添加到post体。这有两个方法:从内存中添加(appendPostData:),或者从文件中添加(appendPostDataFromFile:);

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    3. [request setShouldStreamPostDataFromDisk:YES];  
    4. [request appendPostData:myBigNSData];  
    5. [request appendPostDataFromFile:@"/Users/ben/Desktop/bigfile.txt"];  
    6. [request startSynchronous];</span>  

    这个例子中,我们想直接PUT一个大文件。我们得自己设置setPostBodyFilePath ,ASIHTTPRequest将使用这个文件来作为post体。

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    3. [request setRequestMethod:@"PUT"];  
    4. [request setPostBodyFilePath:@"/Users/ben/Desktop/another-big-one.txt"];  
    5. [request setShouldStreamPostDataFromDisk:YES];  
    6. [request startSynchronous];</span>  

    IMPORTANT:切勿对使用上述函数的request使用setPostBody——他们是互斥的。只有在你要自己建立request的请求体,并且还准备在内存中保持这个请求体时,才应该使用setPostBody。

    1.   

    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机制很简单:

    1. <span style="margin:0px; padding:0px">[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];</span>  

    这样做以后,所有的request都会自动使用cache。如果你愿意,你可以让不同的request使用共享的cache:

    1. <span style="margin:0px; padding:0px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request setDownloadCache:[ASIDownloadCache sharedCache]];</span>  

    你不会被局限于使用单一的cache,你可以想创建多少cache就创建多少cache,只要你喜欢 ^ ^。当你自己创建一个cache,你必须设定cache的路径——这路径必须是一个你拥有写权限的目录。

    1. <span style="margin:0px; padding:0px">ASIDownloadCache *cache = [[[ASIDownloadCache alloc] init] autorelease];  
    2. [cache setStoragePath:@"/Users/ben/Documents/Cached-Downloads"];  
    3. </span>  
    4. <span style="margin:0px; padding:0px">//别忘了 - 你必须自己retaining你自己的cache!  
    5. [self setMyCache:cache];  
    6.   
    7. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    8. [request setDownloadCache:[self myCache]];</span>  

    cache策略

    cache策略是你控制cache中信息的主要方法,控制何时使用cache数据而非重新下载数据。

    每个request的cache策略可是由request的cachePolicy 属性来控制的。cache策略使用掩码来定义,所以你可以二进制“与”操作他们。

    1. <span style="margin:0px; padding:0px">// 每次都向服务器询问是否有新的内容可用,  
    2. // 如果请求失败, 使用cache的数据,即使这个数据已经过期了  
    3. [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy];</span>  

    你可以使用下列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设置:

    1. <span style="margin:0px; padding:0px; font-size:13px">ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    2. [request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];</span>  

    要手动清除cache,调用函数clearCachedResponsesForStoragePolicy:,传入要清除的cache数据的存储策略:

    1. <span style="margin:0px; padding:0px; font-size:13px">[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICachePermanentlyCacheStoragePolicy];</span>  

    其他cache相关的特性

    1. <span style="margin:0px; padding:0px; font-size:13px">// 当你关闭 shouldRespectCacheControlHeaders,cache对象会存储响应数据,而无视  
    2. // 服务器的显式“请勿缓存”声明 (例如:cache-control 或者pragma: no-cache 头)  
    3. [[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];  
    4.   
    5. // 可以设定request的secondsToCache来覆盖服务器设定的内容有效期, 这时,响应数据  
    6. // 会一直被缓存,直到经过secondsToCache秒  
    7. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    8. [request setSecondsToCache:60*60*24*30]; // 缓存30 天  
    9.   
    10. //当request开始执行后,如果响应数据是从缓存中取得的,didUseCachedResponse 会返回YES  
    11. [request didUseCachedResponse];  
    12.   
    13. // 向cache对象索取一个路径来存储相应数据. 这是使用download cache的最有效率的方法,  
    14. // 因为此时,当request完成后,数据不需要被复制到cache中.  
    15. [request setDownloadDestinationPath:  
    16.    [[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request]];</span>  

    编写自己的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连接时自动关闭流量限制。

    1. <span style="margin:0px; padding:0px">// 这将会对WWAN连接下的request进行流量控制(控制到预定义的值)  
    2. // Wi-Fi连接下的 request不会受影响  
    3. // 这个方法仅在iOS上可用  
    4. [ASIHTTPRequest setShouldThrottleBandwidthForWWAN:YES];  
    5.    
    6. // 这将会对WWAN连接下的request进行流量控制(控制到自定义的值)  
    7. // 这个方法仅在iOS上可用  
    8. [ASIHTTPRequest throttleBandwidthForWWANUsingLimit:14800];  
    9.    
    10. // 这将会控移动应用(mobile applications)的流量到预定义的值.  
    11. // 会限制所有requests, 不管request是不是WiFi连接下的 - <span style="margin:0px; padding:0px">使用时要注意</span>  
    12. [ASIHTTPRequest setMaxBandwidthPerSecond:ASIWWANBandwidthThrottleAmount];  
    13.    
    14. // 记录每秒有多少字节的流量 (过去5秒内的平均值)  
    15. NSLog(@"%qi",[ASIHTTPRequest averageBandwidthUsedPerSecond]);<br style="margin:0px; padding:0px"></span>  

    IMPORTANT:在启用流量控制前,请参阅以下条目:

    1.   
    • 流量控制特性是试验型的特性:你自己得承担风险
    • 不要把带宽限制设置得很低——最好不要低于ASIWWANBandwidthThrottleAmount
    • 实际流量往往会比你程序设置的流量稍稍偏高,因为流量的测量并不包含HTTP头。
    • ASIWWANBandwidthThrottleAmount 的值是非官方的,据我所知,官方并没有公布流量限制大小
    • 除非你的程序会下载或者上传大量的数据,否则不要开启流量控制。最好是当即将下载或上传大量数据时才启用它,而其他时间应该禁用它。
    • 这玩意应该会按我描述的情况来工作,但是我并不保证你的app使用了我的流量控制就不会被驳回。
    1. <span style="margin:0px; padding:0px"> </span>  

    ASIHTTPRequest-客户端证书支持

    1. 有时服务器要求提供客户端证书,从1.8版本开始,你可以随request发送证书。  
    1. <span style="margin:0px; padding:0px">// Will send the certificate attached to the identity (identity is a SecIdentityRef)  
    2. [request setClientCertificateIdentity:identity];  
    3.    
    4. // Add an additional certificate (where cert is a SecCertificateRef)  
    5. [request setClientCertificates:[NSArray arrayWithObject:(id)cert]];</span>  

    在iPhone/iPad示例工程中的ClientCertificateTests.m中有一个很有用的函数用来从PKCS12数据创建SecIdentityRef (这个函数仅适用于iOS)。

    1. <span style="margin:0px; padding:0px"> </span>  

    ASIHTTPRequest-使用代理连接

    1.   

    ASIHTTPRequest检测系统的proxy设置并自动将proxy用于request。从1.0.6版本开始,它还支持PAC文件和要求授权的proxy。

    默认情况下,ASIHTTPRequest将尝试自动检测proxy设置。当然,你可以看自己手动设置:

    1. <span style="margin:0px; padding:0px">// 手动设置代理服务器  
    2. NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];  
    3. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    4. [request setProxyHost:@"192.168.0.1"];  
    5. [request setProxyPort:3128];  
    6.   
    7. // 另一种方法, 使用代理配置脚本文件  
    8. // (最好使用本地pac文件)  
    9. [request setPACurl:[NSURL URLWithString:@"path/to/test.pac"]];</span>  

    要求授权的proxy

    在Mac OS上,ASIHTTPRequest可以自动检测到要求授权的proxy的凭据(前提是在系统设定中设置好)。在iOS上,ASIHTTPRequest则无法自动检测出授权凭据,所以你要么手动使用delegate来向你的controller或者用户索取合适的凭据,要么让ASIAuthenticationDialog向用户索取凭据。一旦获得了一个有效的proxy凭据,那么该凭据将被存储到keychian中(前提是启用useKeychainPersistence )并自动重用。

    手动为proxy指定凭据

    1. <span style="margin:0px; padding:0px">NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com"];  
    2. ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];  
    3. [request setProxyHost:@"192.168.0.1"];  
    4. [request setProxyPort:3128];  
    5.   
    6. //为要求授权的proxy设置username 和password  
    7. [request setProxyUsername:@"bencopsey"];  
    8. [request setProxyPassword:@"password"];  
    9.   
    10. // 对于NTLM proxy,还要设置 domain (NTLM proxy功能是未经测试的)  
    11. [request setProxyDomain:@"la.la.land"];</span>  

    使用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 子类.

    1. <span style="margin:0px; padding:0px"> </span>  

    ASIHTTPRequest-其他特性

    1. <span style="margin:0px; padding:0px"> </span>  

    设置user agent

    这样设置用户代理:

    1. <span style="margin:0px; padding:0px">[ASIHTTPRequest setDefaultUserAgentString:@"MyApp 1.0"]</span>  

    如果不设置user agent,ASIHTTPRequest会为你创建一个。例如(Mac OS程序):

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

    你也可以为每个request设置user agent:

    1. <span style="margin:0px; padding:0px">[request setUserAgent:@"MyApp 1.0"]</span>  

    当程序进入后台运行时,继续执行request(iOS)

    1. <span style="margin:0px; padding:0px">// iOS 4以上  
    2. [request setShouldContinueWhenAppEntersBackground:YES];</span>  

    监视网络活动

    1. <span style="margin:0px; padding:0px">//记录过去5秒的平均流量字节/秒  
    2. NSLog(@"%llu",[ASIHTTPRequest averageBandwidthUsedPerSecond]);  
    3.    
    4. if ([ASIHTTPRequest isNetworkInUse]) {  
    5.     // ASIHTTPRequest 进程中有requests正在使用网络  
    6. }</span>  

    禁用自动更新网络连接标示符状态(iOS)

    默认情况下,ASIHTTPRequest在request使用网络连接时,会自动显示网络连接标示符(iOS状态条中)。如果你想自己控制标示符,你可以禁用这个特性:

    1. <span style="margin:0px; padding:0px">[ASIHTTPRequest setShouldUpdateNetworkActivityIndicator:NO];</span>  

    超时自动重试

    设置超时自动重试最大次数为2:

    1. <span style="margin:0px; padding:0px">[request setNumberOfTimesToRetryOnTimeout:2];</span>  

    设置持久连接

    默认情况下,ASIHTTPRequest将会尝试保持对一个服务器的连接以便往后的连接到该服务器的request可以重用这个连接(这个特性可以显著地提高速度,尤其是当你会要进行很多小数据量request时)。当连接到HTTP 1.1服务器或者服务器发送keep-alive头时,持久连接会自动被使用。当服务器显式地发送”Connection:close”头时,持久连接就不会被使用。另外,默认情况下,ASIHTTPRequest不会对包含请求体(例如POST/PUT)的request使用持久连接(从1.8.1版本开始)。通过设置request,你可以强制让此类request使用持久连接:

    1. <span style="margin:0px; padding:0px">[request setRequestMethod:@"PUT"];  
    2. [request setShouldAttemptPersistentConnection:YES];</span>  

    很多服务器不会在响应头中规定持久连接的持久时间,它们可能会在任何一个request完成时候关闭连接。如果一个服务器没有规定持久连接的持久时间,ASIHTTPRequest将会在一个request完成后,保持连接60秒。对于你的服务器设置来时,60可能很长,也可能很短。

    如果这个超时时间太长,那么可能一个request使用这个连接时,服务器可能已经关闭了这个连接。当ASIHTTPRequest遇到连接已关闭错误,它就会在一个新的连接上重试这个request。

    如果这个超时时间太短,而服务器却更想让这个连接保持更长时间,但是ASIHTTPRequest又开启了不必要的新连接,那么这将导致效率降低。

    1. <span style="margin:0px; padding:0px">// 设置持久连接的超时时间为120秒  
    2. [request setPersistentConnectionTimeoutSeconds:120];  
    3.    
    4. // 彻底禁用持久连接  
    5. [request setShouldAttemptPersistentConnection:NO];</span>  

    强制使用HTTP 1.0

    1. <span style="margin:0px; padding:0px">[request setUseHTTPVersionOne:YES];</span>  

    禁用安全证书校验

    如果你有一个自签名的证书,你可能想禁用证书校验来做测试。这里我建议你从一个可信的CA购买证书,并为生产(production)期的app(梦维:app还有测试期等等阶段不是?)启用证书校验。

    1. <span style="margin:0px; padding:0px">[request setValidatesSecureCertificate:NO];</span>  

    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时,这一项很有用。

    1. <span style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"><br style="margin:0px; padding:0px"></span>  
     

    升级到iOS5后ASIHttpRequest库问题及解决方法

    1.   
     

    由于正式版的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的其它方面,到目前为止还没发现问题。
  • 相关阅读:
    封装异常处理之坑
    30multipart/form-data和application/x-www-form-urlencoded的区别(二)urlencoded之自动deocde
    使用MAT时的Shallow Size和 Retained Size的区别
    当动态代理遇到ioc
    线程池的原理
    synchroned原理与对象头(yet)
    mysql压力测试与qps监控
    一种mysql jvm死锁
    Android Jni变量对照表
    结构体中使用函数指针
  • 原文地址:https://www.cnblogs.com/Camier-myNiuer/p/3865827.html
Copyright © 2011-2022 走看看