(四)iOS 网络编程之HTTP、HTTPS、NSURLConnection 和 NSURLSession

在移动互联网时代,几乎所有的应用都用到网络请求,只有通过网络和外界进行数据交互、数据更新,应用才能保持新鲜和活力。网络编程也是 iOS 面试中常问到的问题。下面整理一下 iOS 开发中涉及到的网络编程知识:HTTP、HTTPS、NSURLConnection 和 NSURLSession


(一)HTTP 协议和 HTTPS 协议

HTTP协议

HTTP(Hypertext Transfer Protocol)协议是超文本传输协议,是互联网上应用最为广泛的一种网络协议。简单来说,HTTP 是客户端和服务器端之间请求和应答的标准。

HTTP 协议工作过程

分为4个步骤:

  1. 客户端与服务器需要建立连接。例如,单击某个超链接,浏览器和服务器将建立通信连接。
  2. 建立连接后,客户端发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户端信息和可能的内容。
  3. 服务器接收到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后面是 MIME 信息包括服务器信息、实体信息和可能的内容。
  4. 客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。
HTTPS协议

HTTPS(Secure Hypertext Transfer Protocol)安全超文本传输协议它是一个安全通信通道,它基于HTTP开发,用于在客户计算机和服务器之间交换信息。它使用安全套接字层(SSL)进行信息交换,简单来说它是HTTP的安全版。

HTTPS和HTTP的区别:

1、https协议需要到ca申请证书,一般免费证书很少,需要交费。
2、http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的。
5、HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议要比http协议安全。

App Transport Security(简称ATS)特性

iOS9中新增App Transport Security(简称ATS)特性, 让原来请求时候用到的HTTP,全部都转向TLS1.2协议进行传输,这意味着所有的HTTP协议都强制使用了HTTPS协议进行传输。如果我们在iOS9下直接进行HTTP请求是会报错,系统会告诉我们不能直接使用HTTP进行请求,需要在Info.plist中控制ATS的配置。


(二)NSURLConnection 和 NSURLSession 进行网络请求

NSURLConnection

NSURLConnection 是 iOS 开发中最经典的网络请求方案。虽然在苹果公司推出 NSURLSession 后已经不推荐使用 NSURLConnection 了(NSURLConnection 在 iOS 9 被宣布弃用了),但是在一些早先构建的项目和框架中可能任使用了 NSURLConnection 技术,所以还是有必要了解 NSURLConnection。

NSURLConnection 使用步骤
  1. 创建一个 NSURL 对象,用于设置请求路径。
  2. 创建一个 NSURLRequest 对象,并设置请求头、请求体等请求参数。
  3. 创建一个 NSURLResponse 对象用于接收响应数据,一般用 NSURLResponse 的子类 NSHPPTURLResponse。
  4. 使用 NSURLConnection 发送同步或异步请求。
  5. 可以使用 NSURLConnectionDelegate 监听网络请求的响应。
    具体实现可参考网址 NSURLConnection
NSURLSession

在 iOS 9.0 之后,以前使用的 NSURLConnection 被弃用,苹果推荐使用 NSURLSession 来替换NSURLConnection 完成网路请求相关操作。

NSURLSession 使用步骤

NSURLSession 的使用非常简单,先根据会话对象创建一个请求Task,然后执行该Task即可。
NSURLSessionTask 本身是一个抽象类,在使用的时候,通常是根据具体的需求使用它的几个子类。关系如下:


NSURLSessionTask.png

下面关于 NSURLSession 的 GET 和 POST 的使用直接摘录于 iOS开发网络篇—发送GET和POST请求(使用NSURLSession) 。非常感谢。

NSURLSession GET 请求方法

1)确定请求路径(一般由公司的后台开发人员以接口文档的方式提供),GET请求参数直接跟在URL后面。
2)创建请求对象(默认包含了请求头和请求方法【GET】),此步骤可以省略。
3)创建会话对象(NSURLSession)。
4)根据会话对象创建请求任务(NSURLSessionDataTask)。
5)执行请求 Task。
6)当得到服务器返回的响应后,解析数据(XML 或者 JSON)。
代码如下:
第一种方法:

-(void)getByNSURLSession1
{
    //对请求路径的说明
    //http://120.25.226.186:32812/login?username=520it&pwd=520&type=JSON
    //协议头+主机地址+接口名称+?+参数1&参数2&参数3
    //协议头(http://)+主机地址(120.25.226.186:32812)+接口名称(login)+?+参数1(username=520it)&参数2(pwd=520)&参数3(type=JSON)
    //GET请求,直接把请求参数跟在URL的后面以?隔开,多个参数之间以&符号拼接
    
    //1.确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.创建请求对象
    //请求对象内部默认已经包含了请求头和请求方法(GET)
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.获得会话对象
    NSURLSession *session = [NSURLSession sharedSession];
      
    //4.根据会话对象创建一个Task(发送请求)
    /*
     第一个参数:请求对象
     第二个参数:completionHandler回调(请求完成【成功|失败】的回调)
               data:响应体信息(期望的数据)
               response:响应头信息,主要是对服务器端的描述
               error:错误信息,如果请求失败,则error有值
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        if (error == nil) {
            //6.解析服务器返回的数据
            //说明:(此处返回的数据是JSON格式的,因此使用NSJSONSerialization进行反序列化处理)
            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
            
            NSLog(@"%@",dict);
        }
    }];
    
    //5.执行任务
    [dataTask resume];
}

//这是 NSURLSession 发送GET请求的第一种方法

第二种方法:

-(void)getByNSURLSession2
{
    //1.确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.获得会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    
    //3.根据会话对象创建一个Task(发送请求)
    /*
     第一个参数:请求路径
     第二个参数:completionHandler回调(请求完成【成功|失败】的回调)
               data:响应体信息(期望的数据)
               response:响应头信息,主要是对服务器端的描述
               error:错误信息,如果请求失败,则error有值
     注意:
        1)该方法内部会自动将请求路径包装成一个请求对象,该请求对象默认包含了请求头信息和请求方法(GET)
        2)如果要发送的是POST请求,则不能使用该方法
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //5.解析数据
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        NSLog(@"%@",dict);
        
    }];
    
    //4.执行任务
    [dataTask resume];
}

//这是 NSURLSession 发送GET请求的第二种方法
NSURLSession POST请求方法

1)确定请求路径(一般由公司的后台开发人员以接口文档的方式提供)。
2)创建可变的请求对象(因为需要修改),此步骤不可以省略。
3)修改请求方法为POST。
4)设置请求体,把参数转换为二进制数据并设置请求体。
5)创建会话对象(NSURLSession)。
6)根据会话对象创建请求任务(NSURLSessionDataTask)。
7)执行任务 Task。
8)当得到服务器返回的响应后,解析数据(XML 或者 JSON)。

代码如下:

-(void)postByNSURLSession
{
    //对请求路径的说明
    //http://120.25.226.186:32812/login
    //协议头+主机地址+接口名称
    //协议头(http://)+主机地址(120.25.226.186:32812)+接口名称(login)
    //POST请求需要修改请求方法为POST,并把参数转换为二进制数据设置为请求体
    
    //1.创建会话对象
    NSURLSession *session = [NSURLSession sharedSession];
    
    //2.根据会话对象创建task
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
    
    //3.创建可变的请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //4.修改请求方法为POST
    request.HTTPMethod = @"POST";
    
    //5.设置请求体
    request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
    
    //6.根据会话对象创建一个Task(发送请求)
    /*
     第一个参数:请求对象
     第二个参数:completionHandler回调(请求完成【成功|失败】的回调)
                data:响应体信息(期望的数据)
                response:响应头信息,主要是对服务器端的描述
                error:错误信息,如果请求失败,则error有值
     */
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        //8.解析数据
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
        NSLog(@"%@",dict);
        
    }];
    
    //7.执行任务
    [dataTask resume];
}

// 发送POST请求的方法
NSURLSession 代理方法

有的时候,我们可能需要监听网络请求的过程(如下载文件需监听文件下载进度),那么就需要用到代理方法。
接下来通过代码简单说明NSURLSession中普通网络请求会涉及代理方法的使用。

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, strong) NSMutableData *responseData;
@end

@implementation ViewController

-(NSMutableData *)responseData
{
    if (_responseData == nil) {
        _responseData = [NSMutableData data];
    }
    return _responseData;
}

//当点击控制器View的时候会调用该方法
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self delegateTest];
}

//发送请求,代理方法
-(void)delegateTest
{
    //1.确定请求路径
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
    
    //2.创建请求对象
    //请求对象内部默认已经包含了请求头和请求方法(GET)
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    //3.获得会话对象,并设置代理
    /*
     第一个参数:会话对象的配置信息defaultSessionConfiguration 表示默认配置
     第二个参数:谁成为代理,此处为控制器本身即self
     第三个参数:队列,该队列决定代理方法在哪个线程中调用,可以传主队列|非主队列
     [NSOperationQueue mainQueue]   主队列:   代理方法在主线程中调用
     [[NSOperationQueue alloc]init] 非主队列: 代理方法在子线程中调用
     */
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
    //4.根据会话对象创建一个Task(发送请求)
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    
    //5.执行任务
    [dataTask resume];
}

//1.接收到服务器响应的时候调用该方法
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
    //在该方法中可以得到响应头信息,即response
    NSLog(@"didReceiveResponse--%@",[NSThread currentThread]);
    
    //注意:需要使用completionHandler回调告诉系统应该如何处理服务器返回的数据
    //默认是取消的
    /*
        NSURLSessionResponseCancel = 0,        默认的处理方式,取消
        NSURLSessionResponseAllow = 1,         接收服务器返回的数据
        NSURLSessionResponseBecomeDownload = 2,变成一个下载请求
        NSURLSessionResponseBecomeStream        变成一个流
     */
    
    completionHandler(NSURLSessionResponseAllow);
}

//2.接收到服务器返回数据的时候会调用该方法,如果数据较大那么该方法可能会调用多次
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
    NSLog(@"didReceiveData--%@",[NSThread currentThread]);
    
    //拼接服务器返回的数据
    [self.responseData appendData:data];
}

//3.当请求完成(成功|失败)的时候会调用该方法,如果请求失败,则error有值
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    NSLog(@"didCompleteWithError--%@",[NSThread currentThread]);
    
    if(error == nil)
    {
        //解析数据,JSON解析请参考http://www.cnblogs.com/wendingding/p/3815303.html
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:nil];
        NSLog(@"%@",dict);
    }
}
@end

你可能感兴趣的:((四)iOS 网络编程之HTTP、HTTPS、NSURLConnection 和 NSURLSession)