URL
URL格式:
上图已经说的很清晰了,可以对照下面这个URL参考一下:https://ime.geekbang.org/column/article/169263?a=1&b=2&c=3
scheme:使用的协议
user information:"//"访问资源需要的凭证信息(可省略)
host:"@"符号你要访问的主机地址,可以是域名,也可以是ip
port :":"符号隔开,你要访问的端口号,如果不填,则默认端口为80端口
path:由零或多个“/”符号隔开的字符串,一般用来表示主机上的一个目录或文件地址。
query:“?"隔开,用于给动态网页(如使用CGI、ISAPI、PHP/JSP/ASP/ASP。NET等技术制作的网页)传递参数,可有多个参数,用“&”符号隔开,每个参数的名和值用“=”符号隔开。
fragment:字符串,用于指定网络资源中的片断。例如一个网页中有多个名词解释,可使用fragment直接定位到某一名词解释。
开发过程中会遇到一些URL解析,了解URL组成会给工作带来很大的便利,另外可以了解一下NSURLComponents,URL的解析会更加方便。
HTTP
iOS 原生网络库
1.NSURLConnection
NSURLConnection这个类是在NSURLSession之前进行网络请求使用的类,但是现在基本已经不用了,有兴趣可以了解一下下,反正自己只是瞄了一眼。
2.URLRequest&NSMutableURLRequest
NSURLRequest类封装了网络请求的一些基本元素,一个是URL,一个是请求相关的配置
请求方式:
NSURLRequest默认的请求方式是get请求,如果是post请求,那么我们会使用NSURLRequest的子类NSMutableURLRequest,原因我们可以先看一下NSURLRequest和NSMutableURLRequest关于HTTPMethod,HTTPBody的属性:
@interface NSURLRequest(NSHTTPURLRequest)
@property (nullable, readonly, copy) NSData *HTTPBody;
@property (nullable, readonly, copy) NSString *HTTPMethod;
@end
@interface NSMutableURLRequest(NSMutableHTTPURLRequest)
@property (nullable, copy) NSData *HTTPBody;
@property (copy) NSString *HTTPMethod;
@end
可以发现NSURLRequest中的HTTPBody,HTTPMethod都没有set方法,而HTTPMethod又默认是"Get",至此,原因已经很清晰了。还有一点就是,Get请求的数据是拼接在url后面的,post则需要将数据放在请求体中。
缓存策略:
NSURLRequest为我们提供了设置缓存策略的入口:@property NSURLRequestCachePolicy cachePolicy;我们可以通过cachePolicy来设置缓存策略,cachePolicy是一个枚举:
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
NSURLRequestUseProtocolCachePolicy =0,
NSURLRequestReloadIgnoringLocalCacheData =1,
NSURLRequestReloadIgnoringLocalAndRemoteCacheData =4,
NSURLRequestReloadIgnoringCacheData =NSURLRequestReloadIgnoringLocalCacheData,
NSURLRequestReturnCacheDataElseLoad =2,
NSURLRequestReturnCacheDataDontLoad =3,
NSURLRequestReloadRevalidatingCacheData =5,
};
设置请求头:
//字典类型,返回所有的请求头
@property (nullable, copy) NSDictionary<NSString *, NSString *> *allHTTPHeaderFields;
//添加请求头,注意 ,只添加key,不设置value
- (void)addValue:(NSString *)value forHTTPHeaderField:(NSString *)field;
//为请求头设值
- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(NSString *)field;
设置请求行为:
设置是否使用默认的Cookie处理方法,默认是YES
@property BOOL HTTPShouldHandleCookies;
//设置是否支持蜂窝网络,默认是YES
@property BOOL allowsCellularAccess
//设置请求超时时间
@property NSTimeInterval timeoutInterval;
3.NSURLResponse
首先要明确一点就是不管什么时候我们在进行HTTP请求的时候,实际上返回的都是NSURLResponse的子类:NSHTTPURLResponse对象。NSURLResponse对象并不包含真正的响应的实体数据,只是包含一些响应的实体相关的信息。实体数据是通过代理的回调一部分一部分的返回或者是在请求完成时整个全部返回。数据获取后面说NSURLSession会详细说。
NSHTTPURLResponse属性
//响应的MIME类型
@property (nullable, readonly, copy) NSString *MIMEType;
//预期的响应的实体的长度,常用它来显示进度
@property (readonly) long long expectedContentLength;
//响应的URL
@property (nullable, readonly, copy) NSURL *URL;
4.NSURLSession(敲重点)
关于NSURLSession我们可以这样理解:它是继NSURLConnection之后用来取代NSURLConnection进行网络请求的类,我们可以使用NSURLSession的API来创建一个或多个session对象,每个session对象都管理着一组网络请求任务,然后为每个session加入一系列的task,每个task代表着请求一个特定的URL。
NSURLSession的类型
NSURLSession的类型有四个:sharedSession,default session,ephemeral session,background session,这里只说前两个,如果要了解后两个,自行谷歌。
sharedSession
NSURLSession可以通过sharedSession方法创建一个单例,这种创建方法是不需要传入NSURLConfiguration对象的,也就意味着不能设置代理。但是这样可以应对基本的网络请求。
NSURLSession *session = [NSURLSession sharedSession];
default session
要创建default session需要通过[NSURLSessionConfiguration defaultSessionConfiguration]创建一个defaultConfiguration对象传入进去。default session和sharedSession差不多,但是可以配置更多的信息,并且允许我们为session对象设置代理,这样就可以在代理回调中一部分一部分的收到响应的数据。
NSURLSession *session1 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]delegate:self delegateQueue:delegateQueue] ;
多说几句关于delegateQueue:表示代理工作的队列 必须是NSOperationQueue队列,当NSOperationQueue是 [NSOperationQueue mainQueue] 表示代理在主线程上工作,当NSOperationQueue是[[NSOperationQueue alloc] init]或者nil 表示代理在异步工作
值得注意的是:URLSession 请求本身的网络操作是异步的,无论指定什么队列,都是在异步执行的,这里指定的队列是在此指定的代理的工作队列,表示发生网络事件后,希望在哪一个线程中工作。session本身工作的线程,与代理工作的线程是不一样的。
关于选择:如果完成后需要做复杂(耗时)的处理,可以选择异步队列,如果完成后直接更新UI,可以选择主队列
NSURLSession
上面已经提到了task,所以就再多说说喽:
NSURLSession的API为我们提供了三种类型的task:data task,upload task,download task;后两种是以文件形式上传或者获取数据,表示自己还没整明白。
所以就看看data task吧,基本的网络请求这个就够了,data task使用NSData对象发送数据,也使用NSData对象接收数据,因此其接收收据后是写入内存的。data task经常被用来做简单的,交互性的网络请求。
此外还有一些NSURLSession相关的协议:NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDownloadDelegate,NSURLSessionDataDelegate。其实就是处理一些NSURLSession和NSURLSession的问题的方法的回调,可以了解一下,有点多,以后再整理吧。
5.实现请求
这里以Get请求为例,两种方法实现请求。
1.sharedSession,以block实现网络请求
//========================block=========================
//创建请求会话
NSURLSession *session = [NSURLSession sharedSession];
//创建请求
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.mxnzp.com/api/jokes/list/random"]];
//创建请求任务
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(error) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.sessionButton setTitle:@"session失败啦" forState:UIControlStateNormal];
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
[self.sessionButton setTitle:@"session成功啦" forState:UIControlStateNormal];
});
}
}];
//任务开始
[taskresume];
2.default session,以delegate实现
首先要遵守协议,其次之前说过我们接受到的内容都是NSData类型的,所以需要一个属性来存储数据。
@interface ViewController ()<NSURLSessionDataDelegate>
@property (nonatomic,strong) UIButton *sessionButton;
@property (nonatomic,copy)NSMutableData *data;
@end
创建请求任务
//创建请求会话
NSURLSession *session1 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]delegate:self delegateQueue:delegateQueue] ;
//创建请求
NSURLRequest *request1 = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.mxnzp.com/api/jokes/list/random"]];
//创建请求任务
NSURLSessionTask*task1 = [session1dataTaskWithRequest:request1];
[task1resume];
delegate实现数据获取
#pragma mark - NSURLSessionDataDelegate
//表示收到http响应
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
//回调函数 表示继续请求
completionHandler(NSURLSessionResponseAllow);
//初始化data
self.data = [[NSMutableData alloc]init];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[self.data appendData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if(error) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.sessionButton setTitle:[self.sessionButton.titleLabel.text stringByAppendingString:@" session1失败啦"] forState:UIControlStateNormal];
});
}else{
dispatch_async(dispatch_get_main_queue(), ^{
[self.sessionButton setTitle:[self.sessionButton.titleLabel.text stringByAppendingString:@" session1成功啦"] forState:UIControlStateNormal];
});
}
self.data = nil;
}