ASIHTTPRequest 网络请求

前言

  • 使用 iOS SDK 中的 HTTP 网络请求 API,相当的复杂,调用很繁琐,ASIHTTPRequest 就是一个对 CFNetwork API 进行了封装,并且使用起来非常简单的一套 API,外号 “HTTP终结者”,用 Objective-C 编写,运行效率很高,可以很好的应用在 Mac OS X 系统和 iOS 平台的应用程序中,ASIHTTPRequest 适用于基本的 HTTP 请求,和基于 REST 的服务之间的交互。

  • 可惜作者早已停止更新,有一些潜在的 BUG 无人去解决,很多公司的旧项目里面都残留着它的身影,以前的很多 iOS 项目都是 ASI + SBJson,会不会用 ASI,可以算是检验是否为老牌 iOS 程序员的标准之一。

  • 从 iOS 9 开始 CFNetwork 相关的类和方法开始被废弃,可以使用 AFNetworking 替换 ASIHTTPRequest 的使用。在 iOS 9+ 中使用 ASIHTTPRequest 无需对 App Transport Security Settings 添加设置。

1、ASIHTTPRequest

1.1 ASI 主要特色

  • 通过简单的接口,即可完成向服务端提交数据和从服务端获取数据的工作。
  • 下载的数据,可存储到内存中或直接存储到磁盘中。
  • 能上传本地文件到服务端。
  • 可以方便的访问和操作请求和返回的 Http 头信息。
  • 可以获取到上传或下载的进度信息,为应用程序提供更好的体验。
  • 支持上传或下载队列,并且可获取队列的进度信息。
  • 支持基本、摘要和 NTLM 身份认证,在同一会话中授权凭证会自动维持,并且可以存储在 Keychain(Mac 和 iOS 操作系统的密码管理系统)中。
  • 支持 Cookie。
  • 当应用(iOS 4+)在后台运行时,请求可以继续运行。
  • 支持 GZIP 压缩数据。
  • 内置的 ASIDownloadCache 类,可以缓存请求返回的数据,这样即使没有网络也可以返回已经缓存的数据结果。
  • ASIWebPageRequest 可以下载完整的网页,包括包含的网页、样式表、脚本等资源文件,并显示在 UIWebView /WebView 中。任意大小的页面都可以无限期缓存,这样即使没有网络也可以离线浏览。
  • 支持客户端证书。
  • 支持通过代理发起 Http 请求。
  • 支持带宽限制。在 iOS 平台,可以根据当前网络情况来自动决定是否限制带宽,例如当使用 WWAN(GPRS/Edge/3G) 网络时限制,而当使用 WIFI 时不做任何限制。
  • 支持断点续传。
  • 支持同步和异步请求。

1.2 AFN 与 ASI 的区别

  • 1、底层实现

    • 1)AFN 的底层实现基于 OC 的 NSURLConnection 和 NSURLSession
    • 2)ASI 的底层实现基于纯 C 语言的 CFNetwork 框架
    • 3)因为 NSURLConnection 和 NSURLSession 是在 CFNetwork 之上的一层封装,因此 ASI 的运行性能高于 AFN
  • 2、对服务器返回的数据处理

    • 1)ASI 没有直接提供对服务器数据处理的方式,直接返回的是 NSData/NSString
    • 2)AFN 提供了多种对服务器数据处理的方式
      • (1) JSON 处理-直接返回 NSDictionary 或者 NSArray
      • (2) XML 处理-返回的是 xml 类型数据,需对其进行解析
      • (3) 其他类型数据处理
  • 3、监听请求过程

    • 1)AFN 提供了success 和 failure 两个 block 来监听请求的过程(只能监听成功和失败)
      • success : 请求成功后调用
      • failure : 请求失败后调用
    • 2)ASI 提供了 3 套方案,每一套方案都能监听请求的完整过程(监听请求开始、接收到响应头信息、接受到具体数据、接受完毕、请求失败)
      • 成为代理,遵守协议,实现协议中的代理方法
      • 成为代理,不遵守协议,自定义代理方法
      • 设置 block
  • 4、在文件下载和文件上传的使用难易度

    • 1)AFN
      • 不容易实现监听下载进度和上传进度
      • 不容易实现断点续传
      • 一般只用来下载不大的文件
    • 2)ASI
      • 非常容易实现下载和上传
      • 非常容易监听下载进度和上传进度
      • 非常容易实现断点续传
      • 下载大文件或小文件均可
    • 3)实现下载上传推荐使用 ASI
  • 5、网络监控

    • 1)AFN 自己封装了网络监控类,易使用
    • 2)ASI 使用的是 Reachability,因为使用 CocoaPods 下载 ASI 时,会同步下载 Reachability,但 Reachability 作为网络监控使用较为复杂(相对于 AFN 的网络监控类来说)
    • 3)推荐使用 AFN 做网络监控 AFNetworkReachabilityManager
  • 6、ASI 提供的其他实用功能

    • 1)控制信号旁边的圈圈要不要在请求过程中转
    • 2)可以轻松地设置请求之间的依赖:每一个请求都是一个 NSOperation 对象
    • 3)可以统一管理所有请求(还专门提供了一个叫做 ASINetworkQueue 来管理所有的请求对象)
      • 暂停/恢复/取消所有的请求
      • 监听整个队列中所有请求的下载进度和上传进度

2、ASIHTTPRequest 的使用

2.1 添加 ASIHTTPRequest

ASIHTTPRequest Version Minimum iOS Target Target Notes
1.8.1 -> 1.8.2 iOS 3.0+
0.2 -> 1.8.0
  • ASIHTTPRequest 使用 MRC

  • Objective-C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 添加系统库文件
    CFNetwork.framework
    SystemConfiguration.framework
    MobileCoreServices.framework
    CoreGraphics.framework
    libz.1.1.3.tbd
    libxml2.2.tbd

    // 添加第三方库文件
    ASIHTTPRequest-1.8.2

    // 在 TARGETS -> Builed Settings -> Search Paths -> Header Search Paths 中添加文件路径
    /usr/include/libxml2

    // 在 TARGETS -> Build Phases -> Compile Sources -> ...in .../ASIHTTPRequest 后添加
    -fno-objc-arc

    // 包含头文件
    #import "ASIHTTPRequest.h"
    #import "ASIFormDataRequest.h"

2.2 ASIHTTPRequest 的设置

  • Objective-C

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // 设置请求头
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://api.hudong.com/iphonexml.do?type=focus-c"]];
    [request addRequestHeader:@"Referer" value:@"http://www.dreamingwish.com/"];

    // 设置应用后台运行时是否仍然请求数据
    request.shouldContinueWhenAppEntersBackground = YES;

    // 设置请求超时时重试的次数
    request.numberOfTimesToRetryOnTimeout = 3;

    // 设置 KeepAlive 支持

    // Set the amount of time to hang on to a persistent connection before it should expire to 2 minutes
    request.persistentConnectionTimeoutSeconds = 120;

    // Disable persistent connections entirely
    request.shouldAttemptPersistentConnection = NO;

    // 设置是否显示网络请求信息在 status bar 上
    [ASIHTTPRequest setShouldUpdateNetworkActivityIndicator:NO];

    // 网络状态检查
    BOOL isNetworkInUse = [ASIHTTPRequest isNetworkInUse];

3、ASI 同步 GET 请求

  • 这是 ASIHTTPRequest 最简单的一种使用模式,发送 startSynchronous 消息后即开始在同一线程中执行 HTTP 请求,线程将一直等待直到请求结束(请求成功或者失败)。通过检查 error 属性可以判断请求是否成功或者有错误发生。

  • 要获取返回的文本信息,调用 responseString 方法。如果下载的是二进制文件,例如图片、MP3,则调用 responseData 方法,可以得到一个 NSData 对象。

  • 一般情况下,应该优先使用异步请求代替同步请求,当在主线程中使用 ASIHTTPRequest 同步请求会阻塞主线程的执行,这导致用户界面不响应用户操作,任何动画都会停止渲染,直到请求完成。

  • Objective-C

    • 数据请求

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      NSURL *url = [NSURL URLWithString:@"http://api.hudong.com/iphonexml.do?type=focus-c"];

      // 创建请求
      ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

      // 设置超时时间,可不设置,使用默认
      request.timeOutSeconds = 5;

      // 发送同步请求
      [request startSynchronous];

      // 获得错误信息
      NSError *error = [request error];

      // 网络请求失败
      if (error) {

      // 网络请求成功
      NSLog(@"网络请求失败:\n%@", error);

      } else {

      // 获得服务器的响应,字符串格式
      NSString *responseString = [request responseString];
      NSLog(@"网络请求成功:\n%@", responseString);

      // 获得服务器的响应,NSData 格式
      NSData *responseData = [request responseData];
      textView.text = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
      }
    • 文件下载

      • 通过设置 request 的 setDownloadDestinationPath,可以设置下载文件用的下载目标目录。首先,下载过程文件会保存在 temporaryFileDownloadPath 目录下。如果下载完成会做以下事情:

        • 1,如果数据是压缩的,进行解压,并把文件放在 downloadDestinationPath 目录中,临时文件被删除。
        • 2,如果下载失败,临时文件被直接移到 downloadDestinationPath 目录,并替换同名文件。
      • 如果你想获取下载中的所有数据,可以实现 delegate 中的 request:didReceiveData:方法。但如果你实现了这个方法,request 在下载完后,request 并不把文件放在 downloadDestinationPath中,需要手工处理。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        NSURL *url = [NSURL URLWithString:@"http://www.dreamingwish.com/wp-content/uploads/2011/10/asihttprequest-auth.png"];

        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

        // 设置文件存储路径
        [request setDownloadDestinationPath:@"/Users/JHQ0228/Desktop/asi.png"];

        [request startSynchronous];

        // 获得错误信息
        NSError *error = [request error];

        // 网络请求失败
        if (error) {

        NSLog(@"网络请求失败:\n%@", error);

        } else {

        // 网络请求成功
        NSLog(@"网络请求成功:\n");
        }

4、ASI 异步 GET 请求

  • 请求在后台线程中运行,当请求执行完后再通知调用的线程。这样不会导致主线程进行网络请求时,界面被锁定等情况。

    • 协议方式

      • 在这里实现了两个 delegate 的方法,当数据请求成功时会调用 requestFinished,请求失败时(如网络问题或服务器内部错误)会调用 requestFailed。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        NSURL *url = [NSURL URLWithString:@"http://api.hudong.com/iphonexml.do?type=focus-c"];

        // 创建请求
        ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

        // 设置超时时间,可不设置,使用默认
        request.timeOutSeconds = 5;

        // 设置代理,需遵守 <ASIHTTPRequestDelegate> 协议
        request.delegate = self;

        // 发送异步请求
        [request startAsynchronous];

        // 网络请求成功,协议方法
        - (void)requestFinished:(ASIHTTPRequest *)request {

        }

        // 网络请求失败,协议方法
        - (void)requestFailed:(ASIHTTPRequest *)request {

        }
    • Block 方式

      • 在平台支持情况下,ASIHTTPRequest 1.8 以上支持 block。

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        NSURL *url = [NSURL URLWithString:@"http://api.hudong.com/iphonexml.do?type=focus-c"];

        // 创建请求,加 __weak 除去 block 循环调用警告
        __weak ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];

        // 设置超时时间,可不设置,使用默认
        request.timeOutSeconds = 5;

        // 发送异步请求
        [request startAsynchronous];

        // 网络请求成功
        [request setCompletionBlock:^{

        }];

        // 网络请求失败
        [request setFailedBlock:^{

        }];

5、ASI POST 请求

  • POST 表单

    • ASIFormDataRequest,模拟 Form 表单提交,其提交格式与 Header 会自动识别。文件中的数据是需要时才从磁盘加载,所以只要 web server 能处理,那么上传大文件是没有问题的。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      // 通常数据是以 ’application/x-www-form-urlencoded’ 格式发送的,如果上传了二进制数据或者文件,那么格式将自动变为 ‘multipart/form-data’。

      ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"http://www.dreamingwish.com"]];

      // 没有文件
      [request setPostValue:@"Ben" forKey:@"first_name"];
      [request setPostValue:@"Copsey" forKey:@"last_name"];

      // 发送文件
      [request setFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photo"];

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

      ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"http://www.dreamingwish.com"]];

      // Upload a file on disk
      [request setFile:@"/Users/ben/Desktop/ben.jpg" withFileName:@"myphoto.jpg" andContentType:@"image/jpeg" forKey:@"photo"];

      // Upload an NSData instance
      NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed:@"myphoto.jpg"]);
      [request setData:imageData withFileName:@"myphoto.jpg" andContentType:@"image/jpeg" forKey:@"photo"];

      // 你可以使用 addPostValue 方法来发送相同 name 的多个数据:

      ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:@"http://www.dreamingwish.com"]];

      [request addPostValue:@"Ben" forKey:@"names"];
      [request addPostValue:@"George" forKey:@"names"];
  • PUT 请求、自定义 POST 请求

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

      1
      2
      3
      4
      5
      6
      ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"http://www.dreamingwish.com"]];

      [request appendPostData:[@"This is my data" dataUsingEncoding:NSUTF8StringEncoding]];

      // Default becomes POST when you use appendPostData: / appendPostDataFromFile: / setPostBody:
      [request setRequestMethod:@"PUT"];
文章目录
  1. 1. 前言
  2. 2. 1、ASIHTTPRequest
    1. 2.1. 1.1 ASI 主要特色
    2. 2.2. 1.2 AFN 与 ASI 的区别
  3. 3. 2、ASIHTTPRequest 的使用
    1. 3.1. 2.1 添加 ASIHTTPRequest
    2. 3.2. 2.2 ASIHTTPRequest 的设置
  4. 4. 3、ASI 同步 GET 请求
  5. 5. 4、ASI 异步 GET 请求
  6. 6. 5、ASI POST 请求
隐藏目录