本文主就iOS开发所使用的NSURL进行简要的概述
iOS网络编程之NSURL网络请求
在此之前首先区分URI、URL、URN这三个术语,这将有助于对iOS 中NSURL的理解。命名全称如下:
- URI: Uniform Resource Identifier 统一资源标示
- URL: Uniform Resource Locator 统一资源定位
- URN: UniformResource Name 统一资源名
URL和URN都是URI的子集
URN 定义某事物的身份,而 URL 提供查找该事物的方法,URI可被视为定位符,名称或两者兼备
更详细的定义可参见wiki百科
URL定义
URL定义:scheme://[user:password@][hostname]:[port][absolute-path][?query]
scheme :协议名,不带有连接内容的冒号,iOS中常用的事http(s)、file。此外还有ftp、data、mailto等
本文主要针对http请求进行总结
user:password :认证,其中user为用户名,password为密码。不过这种认证方式安全性较低,较少使用
hostname:表示主机名,如果是file协议,hostname和port将会被省略掉;当使用localhost或127.0.0.1作为主机名时URL将会应用本地机器,相同URL在不同机器上可以应用不同的资源。
port:TCP连接的端口号,如果缺省,那么会使用特定协议的默认端口号:http为80,https为443。
absolute-path:绝对路径,指定了网络资源的路径,其中不可包含问号、回车、空格和换行符
query:查询字符串,与绝对路径之间用“?”分隔,多个参数时用“&”来分隔
HTTP简介
HTTP应用层协议建立在TCP/IP协议之上,首先是建立TCP连接,然后通过HTTP协议规定的格式进行网络通讯,HTTPS与HTTP的主要区别在于TCP连接建立完成之后必须建立SSL会话,并且后面的通讯都是通过SSL会话协商的加密方式加密过的。理解HTTP的核心就是理解HTTP请求和响应的格式:
sequenceDiagram
设备应用 -> 服务器: TCP连接
服务器 -> 设备应用: SSL回话(HTTP没有)
设备应用 -> 服务器: 发送HTTP请求
服务器 -> 设备应用: 接受HTTP响应
HTTP请求:请求行+请求头+请求体
GET /zenggen021151 HTTP/1.1 //请求行
Host: blog.csdn.net //下面均为请求头
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://write.blog.csdn.net/postlist
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6,en-US;q=0.4
//请求体为空
- 请求行为首行部分内容,包含HTTP请求方法、请求URI和HTTP协议版本,请求方法常用的有GET、POST、HEAD、PUT、DELETE等
- 请求头是向服务器提供的额外内容,每个请求必须有一个或多个请求头,Host为必须的请求头;
- 请求体是可选的可以为任意数据,与请求头之间隔一行。
HTTP响应:状态行+响应头+响应体
- 状态行包含HTTP协议版本、请求结果的状态值以及状态描述
- 响应头和响应体与请求头和请求体类似
HTTP/1.1 200 OK //状态行
Server: openresty //下面均为响应头
Date: Sat, 03 Jun 2017 07:50:28 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Keep-Alive: timeout=20
Vary: Accept-Encoding
Cache-Control: private
X-Powered-By: PHP 5.4.28
Content-Encoding: gzip
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" // 响应体,用空行隔开 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
...
iOS中URL加载系统相关使用
NSURL可以轻松管理URL值并访问其指向的内容,NSURL可以指向文件资源或网络资源,并且在使用上没有任何区别,简单的使用方式如下:
NSURLRequest包含加载url内容所需的信息,HTTP(S)中的请求中的所有信息
NSURL *url = [NSURL urlWithString:urlStr];//urlStr 可以引用文件或网络资源
//直接加载url定位资源数据,为同步方法,一般用于加载小文件
NSData *data = [NSData dataWithContentsOfURL:url];
//url请求默认初始化方法,HTTP或HTTPS为GET方法
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//url请求定义缓存策略和超时市场的初始化方法,使用默认属性
NSURLRequest *request1 = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:20];
//可修改的的url请求,修改请求方法以及添加修改请求头等
NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:_testUrl];
[request2 setHTTPMethod:@"POST"];
[request2 setHTTPBody:[@"test body data" dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:@"keep-alive" forHTTPHeaderField:@"Connection"];
NSURLResponse包含加载完毕后的信息数据类型、预计长度、建议命名等
其子类NSHTTPURLResponse还有HTTP响应的状态行、响应头等信息
// 响应状态
@property (readonly) NSInteger statusCode;
// 响应请求头
@property (readonly, copy) NSDictionary *allHeaderFields;
// 响应对应的URL
@property (nullable, readonly, copy) NSURL *URL;
// 响应对应的数据格式
@property (nullable, readonly, copy) NSString *MIMEType;
在iOS7之前使用的是NSURLConnection加载系统,之后是NSURLSession
详细的区别不是本篇文章的重点,需要了解可以看Objc中国上的一篇文章,在这里只对如何加载网络数据做一些总结。
这两种请求方式共用的一系列类有:NSURL
、NSURLRequest
、NSURLResponse
、、NSURLProtocol
、 NSURLCache
、 NSHTTPCookieStorage
、NSURLCredentialStorage
。
NSURLConnection主要是通过NSURLConnectionSynchronousLoading
、NSURLConnectionQueuedLoading
两个类目实现简单的同步异步请求任务,以及通过实现NSURLConnectionDelegate
、NSURLConnectionDataDelegate
、NSURLConnectionDownloadDelegate
的委托方法来更精细的处理整个请求响应过程。
与NSURLConnection相比,NSURLSession提供了配置每个会话的缓存,协议,cookie和证书政策(credential policies),甚至跨应用程序共享它们的能力,网络基础架构和部分应用程序独立工作,而不会互相干扰。NSURLSession使用的是会话任务NSURLSessionTask
的子类NSURLSessionDataTask
、
NSURLSessionUploadTask
、NSURLSessionDownloadTask
,处理数据的加载以及客户端与服务器之间的文件和数据的上传下载服务。同时也有相应的委托NSURLSessionDelegate
、NSURLSessionTaskDelegate
、NSURLSessionDataDelegate
、NSURLSessionDownloadDelegate
、NSURLSessionStreamDelegate
。NSURLSession,它负责处理数据的加载,以及客户端与服务器之间的文件和数据的上传下载服务。NSURLSessionTask与NSURLConnection是及其相似的,使用方式和性能都有很大的改善。
NSURLConnection部分
该套加载系统是通过同名类NSURLConnection来实现加载处理的
- 同步请求处理简单的HTTP请求任务
NSHTTPURLResponse *response;
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
- 异步请求处理简单的HTTP请求任务
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request
queue:queue
completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
}];
- 通过实现NSURLConnectionDataDelegate委托的异步请求
NSURLConnection *connect = [NSURLConnection connectionWithRequest:request delegate:self];
[connect start];
//请求出错时回调
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(@"didFailWithError");
}
//请求发出前时回调,需做重定向,可在此处做处理
-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response{
NSLog(@"willSendRequest");
return request;
}
//请求体发送时回调
-(void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite{
NSLog(@"didSendBodyData");
}
//收到服务器响应时回调,可能被多次调用
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(@"didReceiveResponse");
}
//接收到服务器返回数据时回调,可能被多次调用
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSLog(@"didReceiveData:%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
其他的一些委托方法如下图所示,具体使用可查看头文件中的说明
NSURLSession部分
NSURLSession中简单的请求都是以task来完成的,且均为异步请求。
简单的NSURLSessionTask使用
NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) { }]; //在task创建后还可以做进一步的配置,并不会立即执行,需要手动来使其执行 [task resume]; //上传任务,需要传递要上传的数据 NSData *data; //...data赋值 NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:data completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) { }]; [uploadTask resume]; //下载任务需要在block中返回一个文件路径来存放下载数据,系统首先会创建一个临时文件来存放,下载完成后写入指定文件 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler: ^(NSURL *location, NSURLResponse *response, NSError *error) { NSString *filePath; //filePath为数据下载需要存储的位置 return filePath; }]; [downloadTask resume];
如果读写文件比较大时还可以使用NSURLSessionStreamTask来完成。
通过实现NSURLSessionTaskDelegate委托的异步请求
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] 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{ //在该方法中可以得到响应头信息,即response //注意:需要使用completionHandler回调告诉系统应该如何处理服务器返回的数据 //默认是取消的 /* NSURLSessionResponseCancel = 0, 默认的处理方式,取消 NSURLSessionResponseAllow = 1, 接收服务器返回的数据 NSURLSessionResponseBecomeDownload = 2,变成一个下载请求 NSURLSessionResponseBecomeStream 变成一个流 */ completionHandler(NSURLSessionResponseAllow); } //2.接收到服务器返回数据的时候会调用该方法,如果数据较大那么该方法可能会调用多次 -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ } //3.当请求完成(成功|失败)的时候会调用该方法,如果请求失败,则error有值 -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ }
其他NSURLSession相关委托方法如下图所示
以上就是iOS中NSURL网络请求的一些基本用法,关于缓存、认证、cookie以及一些配置,每一项的详细操作涉及内容都比较多,后面在做总结。