【从0开始的iOS应用开发之旅 - 07】发送一个Http请求

in 从零开始的iOS应用开发之旅 with 0 comment

网络请求是App获取远程数据和资源的一种普遍且重要的方法,目前我们在 App Store 上看到的绝大部分应用都会与网络进行数据交互,所以网络请求在应用开发中,也是绕不过去的重要一环。这里就简单记录一下使用原生方法进行简单的请求必应壁纸的信息。

API如下:https://bing.creepersan.com/document

一个简单的网络请求

在iOS开发中,发送一个简单的请求需要3个组件。

  1. NSURL:统一资源定位符
  2. NSURLRequest:请求参数的定义
  3. NSURLSession:用于完成网路请求相关操作资源数据

当我们需要获取网络上的数据的时候,会把请求的地址封装成为NSURL。然后在NSURL的基础之上,会一并的把一些请求参数、设置(GET、POST请求方法、请求参数、超时时间之类的)封装成一个NSURLRequest请求。拿到这个请求后,调用系统提供的NSURLSession相关函数就能发送到服务器上并接受对应的返回数据。

NSURL

Uniform Resource Locator,统一资源定位符。是一个用于定位一个资源位置的协议(不仅仅是网络请求,本地文件之类的也可以用他描述)。其格式打入如下

[协议类型]://[服务器地址]:[端口号]/[资源层级unix路径]/[文件名]?[查询参数]#[片段ID]

我们在浏览器上输出的那些地址,其实都是符合URL规范的字符串。也就是说,我们接下来要发送的网络请求地址,也是符合URL协议的规范的。

NSURL,就是iOS平台上封装好的一套URL规范,其内部对URL进行了各部分的划分,我们就能通过这个类获得URL地址中的各部分信息了

我们也能在NSURL的头文件中找到这些数据的定义

07

通过这个封装,我们就能免去一些列的解析逻辑,直接从里面取出对应的数据即可

可以通过 requestWithURL 函数进行请求对象的生成

NSURLRequest

有了上面提及到的NSURL后,我们就能定位我们想要获取到的资源的路径了。但是光知道一个路径,还不足以把对应的数据取到手。URL只是Http请求中的其中一个重要数据,但是并不是所有数据。我们还需要更多的信息,比如说 请求方法(GET、POST之类的),请求参数,Header,Cookie之类的信息。而且,对于一些请求可能还会后更多自定义的设置(例如指定请求的超时时间增等)。

所以,为了把这些数据、设置和NSURL打包为一个整体,NSURLRequest便由此而来。

NSURLRequst对象就代表着一个请求,包含NSURL对象、请求方法、请求头、请求体等等信息

NSURLSession

有了前面的请求后,便有了发起请求的数据了。要发送这个请求并获得数据进行处理,可以通过NSURLSession处理(以前是NSURLConnection,现已弃用)。其作用主要有

08

值得注意的是,在使用NSURLSession的过程中不要每一个请求都创建一个NSURLSession。应该相同配置和策略的请求使用一个NSURLSession,因为系统会对这个NSURLSession进行统一的管理

组织结构如下图

09

要创建一个NSURLSession,我们可以通过这两个函数进行创建自定义的配置和策略的对象

10

我们可以注意到,其配置都是存放在 NSURLSessionConfiguration 中,其内部主要提供了这些设置

如果我们没有什么特殊的要求的话,也可以使用系统提供的默认的NSURLSession——sharedSession

11

获取到了NSURLSession后,我们需要把NSURLRequest抓换为对应的Task,然后通过操作Task进行数据的请求的加载,并通过delegate获得不同阶段网络请求的回调。而根据不同的请求策略,可以分为以下四种Task

  1. dataTask:处理json之类的简单的数据流
  2. downloadTask:大数据下载,断点续存和下载进度等
  3. uploadTask:数据上传
  4. streamTask:数据流

对应的task的转换,可以通过这些函数进行转换

12

对应Task的继承关系可以参考下图

13

dataTask有以下几种状态

14

task创建时,默认为suspend状态,当设置为resume后,则进行请求

请求完成后,获取对应的请求的阶段以及对应的数据有2种方式获取到

一种是通过block的方式,在请求时传入block,那么在不同阶段的数据回调时,就会自动执行block中的逻辑。

15

另外一种是通过delegate的方式,在请求的阶段中,回调到delegate中对数据进行处理

16

需要注意的是,新版本的iOS默认是支持https请求但不支持http请求的,如果需要支持,则需要在info.plist中加入这段内容

17

发起网络请求

根据上面的描述,要发起一个网络请求,首先得有一个NSURL,要创建一个NSURL,我们可以从字符串中创建一个NSURL

    NSString *urlString = @"https://bing.creepersan.com/api/v1/url?page=1&count=12";
    NSURL *url = [NSURL URLWithString:urlString];

拿到了对应的NSURL后,继续用它生成NSURLRequest

    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];

不过 NSURLRequest requstWithURL 拿到的是只读的NSURLRequest,其内部的一些值是不可以进行设置的,如需进行设置,也可以通过 NSMutableURLRequest 进行请求的生成

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:url];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:nil];

有了请求的数据与配置后,就是通过NSURLSession进行请求了

接口返回的数据是简单的JSON字符串,因此可以使用默认的session创建dataTask

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:urlRequest];

然后就是请求网络并获取回调了

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"%@", [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];

整体代码如下所示

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSString *urlString = @"https://bing.creepersan.com/api/v1/url?page=1&count=12";
    NSURL *url = [NSURL URLWithString:urlString];
    
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
    
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"%@", [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    
    [task resume];
    
}

编译运行,可以看到控制台输出了接口返回的数据

18

网络请求完成