ios知识

iOS网络(二)-HTTP、HTTPS

2021-10-15  本文已影响0人  搬砖的crystal

一、URL

URL的全称是Uniform Resource Locator(统一资源定位符)。
通过1个URL,能找到互联网上唯一的1个资源。
URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL。

URL中常见的协议

(1)HTTP
超文本传输协议,访问的是远程的网络资源,格式是http://
http协议是在网络开发中最常用的协议。
(2)file
访问的是本地计算机上的资源,格式是file://(不用加主机地址)
(3)mailto
访问的是电子邮件地址,格式是mailto:
(4)FTP
访问的是共享主机的文件资源,格式是ftp://

URN、URI

URN:Uniform Resource Name,统一资源名称,指互联网上某一独一无二的资源的名称。
URI:Uniform Resource Identifier,统一资源标志符,是标志互联网上某一资源的字符串,它包含URL和URN。所以,URN如同一个人的名称,URL代表一个人的地址。

二、HTTP

HTTP的全称是Hypertext Transfer Protocol,超文本传输协议。
HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
HTTP属于应用层面向对象协议。

1.通信过程

(1)请求:客户端向服务器索要数据。
(2)响应:服务器返回客户端相应的数据。

2.请求

HTTP协议规定:1个完整的由客户端发给服务器的HTTP请求中包含以下内容:

3.响应

客户端向服务器发送请求,服务器应当做出响应,即返回数据给客户端。
HTTP协议规定:1个完整的HTTP响应中包含以下内容:

4.常见状态码
5.发送请求的方法

在HTTP/1.1协议中,定义了8种发送http请求的方法:GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH。最常用的是GET和POST。GET和POST的主要区别表现在数据传递上。

GET

在请求URL后面以?的形式跟上发给服务器的参数,多个参数之间用&隔开,比如:http://ww.test.com/login?username=123&pwd=234&type=JSON
由于浏览器和服务器对URL长度有限制,因此在URL后面附带的参数是有限制的,通常不能超过1KB。

POST

发给服务器的参数全部放在请求体中
理论上,POST传递的数据量没有限制(具体还得看服务器的处理能力)。

对比

(1)如果要传递大量数据,比如文件上传,只能用POST请求
(2)GET的安全性比POST要差些,如果包含机密\敏感信息,建议用POST
(3)如果仅仅是索取数据(数据查询),建议使用GET
(4)如果是增加、修改、删除数据,建议使用POST

三、OC原生网络类

1.NSURLConnection

iOS9已弃用

2.NSURLSession

使用简单,先根据对象创建一个Task,然后执行Task即可。

(1)NSURLSessionConfiguration

用于配置NSURLSession工作模式以及网络设置。

//工作模式
//普通模式:可以使用缓存
@property (class, readonly, strong) NSURLSessionConfiguration *defaultSessionConfiguration;
//瞬时模式:不使用缓存
@property (class, readonly, strong) NSURLSessionConfiguration *ephemeralSessionConfiguration;
//后台模式:在后台时仍能进行下载操作,需要唯一的identifier标识
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0));

//允许使用蜂窝数据
@property BOOL allowsCellularAccess;
(2)NSURLSession获取
//共享会话,使用全局的cookie,缓存数据
@property (class, readonly, strong) NSURLSession *sharedSession;
//使用配置好的configuration
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration;
//与第二种类似,制定了delegate
+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;
(3)NSURLSessionTask

会话任务,通过NSURLSession创建,有下面3种常用子类:

NSURLSessionDataTask

最普通的网络访问,多用来获取xml或者json。创建后的NSURLSessionTask需要调用resume才会执行。

NSURLSessionDownLoadTask

用来处理下载任务。

NSURLSessionUploadTask

用来处理上传任务,NSURLSessionDataTask的子类。

(4)发送请求
    NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    request.HTTPBody = [@"" dataUsingEncoding:NSUTF8StringEncoding];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error == nil) {
            NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
            NSLog(@"%@",dic);
        }
    }];
    [dataTask resume];
(5)代理方法
#import "DJViewController.h"
@interface DJViewController ()<NSURLSessionDataDelegate>

@end

@implementation DJViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSURL *url = [NSURL URLWithString:@"https://www.baidu.com"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    request.HTTPBody = [@"" dataUsingEncoding:NSUTF8StringEncoding];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];
    [dataTask resume];
    
    
}


//接收服务器响应的时候调用该方法
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    /*
     需要使用completionHandler回调告诉系统如何处理服务器返回的数据,默认是取消
    NSURLSessionResponseCancel = 0,//取消
    NSURLSessionResponseAllow = 1,//接收服务器返回的数据
    NSURLSessionResponseBecomeDownload = 2,//变成下一个请求
    NSURLSessionResponseBecomeStream//变成一个流
    */
    completionHandler(NSURLSessionResponseAllow);
}
//接收到服务器返回数据会调用该方法,如果数据较大,那么该方法会调用多次
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
    
}
//当请求完成的时候会调用该方法
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    
}

@end
3.CFNetwork

CFNetwork是ISO中一个比较底层的网络框架,C语言编写,可以控制一些更底层的东西,如各种常用网络协议、Socket通讯等。

(1)CFNetwork结构
#import "DJViewController.h"
#import <CFNetwork/CFNetwork.h>
@interface DJViewController ()<NSURLSessionDataDelegate>
@property(nonatomic,strong)NSMutableData *imageData;
@end

@implementation DJViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    
    CFStringRef urlStr = CFSTR("http://pics.sc.chainaz.com/files/pic/pic9/201605/apic20649.jpg");
    CFStringRef method = CFSTR("GET");
    CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, NULL);
    CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault, method, url, kCFHTTPVersion1_1);
    CFRelease(url);
    CFReadStreamRef readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, request);
    CFRelease(request);
    //设置流的context,这里将self传入,用于回调
    CFStreamClientContext ctx = {0,(__bridge  void *)(self),NULL,NULL,NULL};
    //设置回调事件,用于监听网络事件
    CFOptionFlags event = kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered;
    CFReadStreamSetClient(readStream, event, myCallBack, &ctx);
    //打开输入流
    CFReadStreamOpen(readStream);
    //将流加入到runloop中
    CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    //开启runloop
    CFRunLoopRun();
    
}
//回调函数
void myCallBack(CFReadStreamRef stream,CFStreamEventType type,void *clientCallBackInfo){
    DJViewController *selfClass = (__bridge  DJViewController *)clientCallBackInfo;
    if (type == kCFStreamEventHasBytesAvailable) {
        UInt8 buff[255];
        CFIndex length = CFReadStreamRead(stream, buff, 255);
        if (!selfClass.imageData) {
            selfClass.imageData = [NSMutableData data];
        }
        [selfClass.imageData appendBytes:buff length:length];
    }
    else if (type == kCFStreamEventEndEncountered) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        //关闭流
        CFReadStreamClose(stream);
        //将流从runloop中移除
        CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
    }
}
@end
4.AFNetworking
(1)NSURLSession网络请求模块
(2)Reachability监测网络状态模块

AFNetworkReachabilityManager

(3)Security安全策略模块

AFSecurityPolicy
iOS项目将服务器端的证书保存导入到项目中,AFN根据项目中的服务器证书来进行验证,验证服务器,保证访问服务器的安全性。
验证证书的模式有三种:
AFSSLPinningModeNone不验证
AFSSLPinningModePublicKey只验证公钥
AFSSLPinningModeCertificate验证证书的所有内容

(4)Serialization序列化

AFURLRequestSerialization
AFURLResponseSerialization

(5)UIKit UI相关的一些类目
(6)原理概述

AFNetworking是对NSURLSessionTask的封装。AFHTTPSessionManager继承AFURLSessionManager对网络请求进行管理,使用AFURLRequestSerialization对网络请求进行封装,使用AFURLResponseSerialization对响应体进行处理,使用AFSecurityPolicy对服务器证书进行校验。支持HTTPS协议,支持本地证书和服务器证书进行对比验证。AFN数据传递主要使用block和Notification方式。

(7)请求过程

1)GET/POST方法调用抽象的请求方法,指明请求参数,调用全能数据请求方法,指明数据请求方式和参数。
2)对请求进行序列化,如果序列化失败,就执行failure block。
3)为每一个NSURLSessionDataTask的dataTask增加代理。
4)对每一个NSURLSessionDataTask的dataTask增加代理的具体实现,对dataTask设置请求之后的回调delegate和处理block。

三、HTTPS

HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。
HTTPS 在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP之间)。这个系统提供了身份验证与加密通讯方法。

1.SSL

SSL(Secure Sockets Layer 安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层与应用层之间对网络连接进行加密。
SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。
SSL协议可分为两层:
SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。
SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

(1)SSL单向认证具体过程

1)客户端向服务器传送客户端SSL协议的版本号,加密算法的种类,产生的随机数,以及其他服务器和客户端之间通讯所需要的各种信息。
2)服务器向客户端传送SSL协议的版本号,加密算法的种类,随机数以及其他相关信息,同时服务器还将向客户端传送自己的证书。
3)客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的CA是否可靠,发行者证书的公钥能否正确解开服务器证书的"发行者的数字签名",服务器证书上的域名是否和服务器的实际域名相匹配。如果合法性验证没有通过,通讯将断开;如果合法性验证通过,将继续进行第四步。
4)用户端随机产生一个用于后面通讯的"对称密码",然后用服务器的公钥(服务器的公钥从步骤2中的服务器的证书中获得)对其加密,然后将加密后的"预主密码"传给服务器。
5)如果服务器要求客户的身份认证(在握手过程中为可选),用户可以建立一个随机数然后对其进行数据签名,将这个含有签名的随机数和客户自己的证书以及加密过的"预主密码"一起传给服务器。
6)如果服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的CA是否可靠,发行CA 的公钥能否正确解开客户证书的发行CA的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验如果没有通过,通讯立刻中断;如果验证通过,服务器将用自己的私钥解开加密的"预主密码 ",然后执行一系列步骤来产生主通讯密码(客户端也将通过同样的方法产生相同的主通讯密码)。
7)服务器和客户端用相同的主密码即"通话密码",一个对称密钥用于SSL协议的安全数据通讯的加解密通讯。同时在SSL通讯过程中还要完成数据通讯的完整性,防止数据通讯中的任何变化。
8)客户端向服务器端发出信息,指明后面的数据通讯将使用的步骤7中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。
9)服务器向客户端发出信息,指明后面的数据通讯将使用的步骤7中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。
10)SSL的握手部分结束,SSL安全通道的数据通讯开始,客户和服务器开始使用相同的对称密钥进行数据通讯,同时进行通讯完整性的检验。
SSL单向认证只要求站点部署了ssl证书就行,任何用户都可以去访问(IP被限制除外等),只是服务端提供了身份认证。

(2)SSL双向认证具体过程

1)客户端发送一个连接请求给安全服务器。
2) 服务器将自己的证书,以及同证书相关的信息发送给客户端。
3)客户端检查服务器送过来的证书是否是由自己信赖的CA中心(如沃通CA)所签发的。如果是,就继续执行协议;如果不是,客户端就给客户一个警告消息:警告客户这个证书不是可以信赖的,询问客户是否需要继续。
4)接着客户端比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,如果是一致的,客户端认可这个服务器的合法身份。
5)服务器要求客户端发送自己的证书。收到后,服务器验证客户端的证书,如果没有通过验证,拒绝连接;如果通过验证,服务器获得客户端的公钥。
6)客户端告诉服务器自己所能够支持的通讯对称密码方案。
7) 服务器从客户端发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户端的公钥加过密后通知浏览器。
8)客户端针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。
9)服务器接收到客户端送过来的消息,用自己的私钥解密,获得通话密钥。
10) 服务器、客户端接下来的通讯都是用对称密码方案,对称密钥是加过密的。
双向认证则是需要服务端与客户端提供身份认证,只能是服务端允许的客户能去访问,安全性相对于要高一些。

(3)SSL双向认证和SSL单向认证的区别

双向认证 SSL 协议要求服务器和用户双方都有证书。单向认证 SSL 协议不需要客户拥有CA证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的(这并不影响 SSL 过程的安全性)密码方案。这样,双方具体的通讯内容,就是加过密的数据,如果有第三方攻击,获得的只是加密的数据,第三方要获得有用的信息,就需要对加密的数据进行解密,这时候的安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通讯密钥长度足够的长,就足够的安全。这也是我们强调要求使用128位加密通讯的原因。

2. HTTPS使用NSURLSession请求

#import "ViewController.h"

@interface ViewController ()<NSURLSessionDataDelegate>

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    /*
    HTTPS请求的时候:
    [1] 证书是受信任的,什么都不用做
    [2] 证书是不受信任的,是自签名的
        (1) 修改配置文件,禁用ATS特性
        (2) 信任并安装(数字证书)
    */

    //    12306(之前不是ca认证这里仍然使用该网站举例)
        NSURL *url = [NSURL URLWithString:@"https://kyfw.12306.cn/otn/"];

        NSURLSession *session = [NSURLSession sessionWithConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
        
        NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
               
               NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
               
        }];
           
        [dataTask resume];
    
    
}

#pragma mark - NSURLSessionDataDelegate
/*
challenge:挑战,质询
当我们发送的是一个HTTPS请求的时候就会调用该方法,需要在该方法中处理证书
NSURLAuthenticationMethodServerTrust:服务器信任
HTTP:80
HTTPS:443
*/
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler{
    
    
    NSLog(@"%@",challenge.protectionSpace);
     /*
       NSURLSessionAuthChallengeUseCredential = 0, 使用证书
       NSURLSessionAuthChallengePerformDefaultHandling = 1,  忽略证书
       NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 请求被取消,证书被忽略
       NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒绝
        */
    
    //判断只有当时NSURLAuthenticationMethodServerTrust的时候才安装这个证书
       if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
           return;
       }
    
    //根据服务器中的保护控件的服务器信任,来创建一个认证信息
    NSURLCredential *credential = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
    completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
    
}

@end
3.HTTPS使用AFNetworking发送请求
#import "ViewController.h"
#import "AFNetworking.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    /**
     //证书受信任
     
    //01 创建会话管理者对象
     AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
     //修改对响应的序列化方式
     manager.responseSerializer = [AFHTTPResponseSerializer serializer];
     
     //02 发送请求
     [manager GET:@"https://www.alipay.com/" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
         
         NSLog(@"%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);
     } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
         NSLog(@"error---%@",error);
     }];
    */
    
    
    //01 创建会话管理者对象
     AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
     //修改对响应的序列化方式
     manager.responseSerializer = [AFHTTPResponseSerializer serializer];
     
     //设置AFN中的安全配置
    //01 允许接收无效的证书
     manager.securityPolicy.allowInvalidCertificates = YES;
    //02 不做域名验证
     manager.securityPolicy.validatesDomainName = NO;
     //03 修改info.plist文件ATS
     
     //02 发送请求
     [manager GET:@"https://kyfw.12306.cn/otn/" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
         
         NSLog(@"%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);
     } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
         NSLog(@"error---%@",error);
     }];
     
}

/**
 AFNetworking:中的类AFSecurityPolicy说明:
 
 AFSecurityPolicy,内部有三个重要的属性,如下:

 AFSSLPinningMode SSLPinningMode;    //该属性标明了AFSecurityPolicy是以何种方式来验证
 BOOL allowInvalidCertificates;      //是否允许不信任的证书通过验证,默认为NO
 BOOL validatesDomainName;           //是否验证主机名,默认为YES

 "AFSSLPinningMode"枚举类型有三个值,分别是AFSSLPinningModeNone、AFSSLPinningModePublicKey、AFSSLPinningModeCertificate。

 "AFSSLPinningModeNone"代表了AFSecurityPolicy不做更严格的验证,"只要是系统信任的证书"就可以通过验证,不过,它受到allowInvalidCertificates和validatesDomainName的影响;

 "AFSSLPinningModePublicKey"是通过"比较证书当中公钥(PublicKey)部分"来进行验证,通过SecTrustCopyPublicKey方法获取本地证书和服务器证书,然后进行比较,如果有一个相同,则通过验证,此方式主要适用于自建证书搭建的HTTPS服务器和需要较高安全要求的验证;

 "AFSSLPinningModeCertificate"则是直接将本地的证书设置为信任的根证书,然后来进行判断,并且比较本地证书的内容和服务器证书内容是否相同,来进行二次判断,此方式适用于较高安全要求的验证。

 如果HTTPS服务器满足ATS默认的条件,而且SSL证书是通过权威的CA机构认证过的,那么什么都不用做。如果上面的条件中有任何一个不成立,那么都只能修改ATS配置。

 
 */

@end

四、HTTPS和HTTP的区别

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

上一篇 下一篇

猜你喜欢

热点阅读