分析一下iOS网络请求的使用
前言:苹果官方提供的网络请求api有两种: nsurlconnection、nsurlsession。
还有,目前的用的最多是主流框架:afnetworking
ios 7之前,只有 nsurlconncetion
ios 9之后,苹果官方放弃nsurlconnection,推荐使用nsurlsession
本文将介绍ios原生api和afn的使用。
苹果官方api:
以下将分别讲述这两种请求的简单使用:
nsurlconnection:
-(void)demo1{ //访问百度首页 //1. 创建一个网络请求 nsurl *url = [nsurl urlwithstring:@"https://m.baidu.com"]; nsurlrequest *request = [nsurlrequest requestwithurl:url]; //2. 发送网络请求 网络请求是个耗时操作,在子线程发送 //第一种发送网络请求的方式 /* * 利用 nsurlconnection 发送一个异步的网络请求 * * @param nsurlrequest 网络请求 * * @return */ //queue:操作队列,决定网络请求完成后的block(completionhandler) 回调在那条线程执行 //[nsoperationqueue mainqueue] 主线程 //completionhandler :block 回调:网络请求完成之后,就会自动调用这个 block [nsurlconnection sendasynchronousrequest:request queue:[nsoperationqueue mainqueue] completionhandler:^(nsurlresponse * _nullable response, nsdata * _nullable data, nserror * _nullable connectionerror) { //response : 响应:服务器的响应 //data:二进制数据:服务器返回的数据。(就是我们想要的内容) //coonectionerror:链接错误的信息 nslog(@"网络响应:response:%@",response); //根据返回的二进制数据,生成字符串!nsutf8stringencoding:编码方式 nsstring *html = [[nsstring alloc]initwithdata:data encoding:nsutf8stringencoding]; //在客户端直接打开一个网页! //客户端服务器:uiwebview //实例化一个客户端浏览器 uiwebview *web = [[uiwebview alloc]initwithframe:self.view.bounds]; //加载html字符串:baseurl:基准的地址:相对路径/绝对路径 [web loadhtmlstring:html baseurl:nil]; //将浏览器加载到view上 [self.view addsubview:web]; // //在本地保存百度首页 // [data writetofile:@"/users/liu/desktop/baidu.html" atomically:yes]; nslog(@"网路链接错误 connectionerror响应:response:%@",connectionerror); }]; }nsurlsession:
//nsurlsession -(void)demo2{ //访问百度首页 //1. 创建一个网络请求 nsurl *url = [nsurl urlwithstring:@"https://m.baidu.com"]; //2.创建请求对象 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) { //response : 响应:服务器的响应 //data:二进制数据:服务器返回的数据。(就是我们想要的内容) //error:链接错误的信息 nslog(@"网络响应:response:%@",response); //根据返回的二进制数据,生成字符串!nsutf8stringencoding:编码方式 nsstring *html = [[nsstring alloc]initwithdata:data encoding:nsutf8stringencoding]; //在客户端直接打开一个网页! //客户端服务器:uiwebview //将浏览器加载到view上 dispatch_async(dispatch_get_main_queue(), ^{ //实例化一个客户端浏览器 uiwebview *web = [[uiwebview alloc]initwithframe:self.view.bounds]; //加载html字符串:baseurl:基准的地址:相对路径/绝对路径 [web loadhtmlstring:html baseurl:nil]; [self.view addsubview:web]; }); // //在本地保存百度首页 // [data writetofile:@"/users/liu/desktop/baidu.html" atomically:yes]; } ]; //5.执行任务 [datatask resume]; }
使用nsurlsession发送get请求的方法和nsurlconnection类似,整个过程如下:
1)确定请求路径(一般由公司的后台开发人员以接口文档的方式提供),get请求参数直接跟在url后面
2)创建请求对象(默认包含了请求头和请求方法【get】),此步骤可以省略
3)创建会话对象(nsurlsession)
4)根据会话对象创建请求任务(nsurlsessiondatatask)
5)执行task
6)当得到服务器返回的响应后,解析数据(xml|json|http)
使用nsurlsession发送post请求的方法和nsurlconnection类似,整个过程如下:
1)确定请求路径(一般由公司的后台开发人员以接口文档的方式提供)
2)创建可变的请求对象(因为需要修改),此步骤不可以省略
3)修改请求方法为post
4)设置请求体,把参数转换为二进制数据并设置请求体
5)创建会话对象(nsurlsession)
6)根据会话对象创建请求任务(nsurlsessiondatatask)
7)执行task
8)当得到服务器返回的响应后,解析数据(xml|json|http)
//post方法 //1.创建会话对象 nsurlsession *session=[nsurlsession sharedsession]; //2.根据会话对象创建task nsurl *url=[nsurl urlwithstring:@"https://123.207.175.144/test1.php"]; //3.创建可变的请求对象 nsmutableurlrequest *request=[nsmutableurlrequest requestwithurl:url]; //4.修改请求方法为post request.httpmethod=@"post"; //5.设置请求体 request.httpbody=[@"login=1" 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];
有的时候,我们可能需要监听网络请求的过程(如下载文件需监听文件下载进度),那么就需要用到代理方法。
//代理方法 #import "viewcontroller.h" @interface viewcontroller () @property (nonatomic, strong) nsmutabledata *responsedata; @end @implementation viewcontroller -(nsmutabledata *)responsedata { if (_responsedata == nil) { _responsedata = [nsmutabledata data]; } return _responsedata; } - (void)viewdidload { [super viewdidload]; // do any additional setup after loading the view, typically from a nib. //[self performselector:@selector(getandsynchronousmethod)]; [self delegatetest]; } -(void)delegatetest { //1.确定请求路径 nsurl *url = [nsurl urlwithstring:@"https://123.207.175.144/test1.php?login=1"]; //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) { //解析数据 nsdictionary *dict = [nsjsonserialization jsonobjectwithdata:self.responsedata options:kniloptions error:nil]; nslog(@"%@",dict); } } @end
如果返回的字符有汉字,可以为nsdictionary提供一个分类,重写系统中的方法。
//重写dictionary #import "nsdictionary+log.h" @implementation nsdictionary (log) -(nsstring *)descriptionwithlocale:(id)locale indent:(nsuinteger)level { //初始化可变字符串 nsmutablestring *string = [nsmutablestring string]; //拼接开头[ [string appendstring:@"["]; //拼接字典中所有的键值对 [self enumeratekeysandobjectsusingblock:^(id _nonnull key, id _nonnull obj, bool * _nonnull stop) { [string appendformat:@"%@:",key]; [string appendformat:@"%@",obj]; }]; //拼接结尾] [string appendstring:@"]"]; return string; } @end
afnetworking:
afnetworking开源库封装了原生的方法,
ios9.0之后,
由于nsurlconnection的弃用,
afnetworking的使用也有一些改变。
get请求:注:使用前需要导入afn框架:afn框架地址
//get请求 -(void)demo1{ nsstring *urlstring = @"https://www.liubaiqi.cn"; afhttpsessionmanager *manger =[afhttpsessionmanager manager]; [manger get:urlstring parameters:nil progress:^(nsprogress * _nonnull downloadprogress) { } success:^(nsurlsessiondatatask * _nonnull task, id _nullable responseobject) { nslog(@"成功"); } failure:^(nsurlsessiondatatask * _nullable task, nserror * _nonnull error) { nslog(@"%@",error); }]; }post请求:
//post请求 -(void)demo2{ nsstring *urlstring = @"https://192.168.1.101:8080"; afhttpsessionmanager *manger =[afhttpsessionmanager manager]; nsmutabledictionary *parameter= @{@"":@"",@"":@""}; [manger post:urlstring parameters:parameter progress:^(nsprogress * _nonnulluploadprogress){ }success:^(nsurlsessiondatatask * _nonnull task, id _nullable responseobject) { nslog(@"成功"); } failure:^(nsurlsessiondatatask * _nullable task, nserror * _nonnull error) { nslog(@"%@",error); }]; }download请求:
//download请求 -(void)demo3{ //1. 创建nsurlsessionconfiguration nsurlsessionconfiguration *configuration = [nsurlsessionconfiguration defaultsessionconfiguration]; //2. 创建管理者对象 afurlsessionmanager *manager = [[afurlsessionmanager alloc]initwithsessionconfiguration:configuration]; //3. 设置url nsurl *url = [nsurl urlwithstring:@"https://127.0.0.1/1.mp4"]; //4. 创建请求对象 nsurlrequest *request = [nsurlrequest requestwithurl:url]; //5. 下载任务 nsurlsessiondownloadtask *downloadtask = [manager downloadtaskwithrequest:request progress:^(nsprogress * _nonnull downloadprogress) { //打印下载进度 nslog(@"%lf",1.0*downloadprogress.completedunitcount/downloadprogress.totalunitcount); } destination:^nsurl * _nonnull(nsurl * _nonnull targetpath, nsurlresponse * _nonnull response) { //设置下载路径 nsurl *documentsdirectoryurl = [[nsfilemanager defaultmanager]urlfordirectory:nsdocumentdirectory indomain:nsuserdomainmask appropriateforurl:nil create:no error:nil]; return [documentsdirectoryurl urlbyappendingpathcomponent:[response suggestedfilename]]; } completionhandler:^(nsurlresponse * _nonnull response, nsurl * _nullable filepath, nserror * _nullable error) { //下载完成 nslog(@"file downloaded to : %@",filepath); }]; //启动任务 [downloadtask resume]; }upload请求:
//upload请求 -(void)demo4{ //创建nsurlsessionconfiguration nsurlsessionconfiguration *configuration = [nsurlsessionconfiguration defaultsessionconfiguration]; //创建管理者对象 afurlsessionmanager *manager = [[afurlsessionmanager alloc]initwithsessionconfiguration:configuration]; //设置url nsurl *url = [nsurl urlwithstring:@"https://127.0.0.1"]; //创建请求对象 nsurlrequest *request = [nsurlrequest requestwithurl:url]; //文件路径 nsurl *filepath = [nsurl fileurlwithpath:@"file://users/liu/desktop/note"]; //上传任务 nsurlsessionuploadtask *uploadtask = [manager uploadtaskwithrequest:request fromfile:filepath progress:nil completionhandler:^(nsurlresponse * _nonnull response, id _nullable responseobject, nserror * _nullable error) { if(error){ //错误 nslog(@"error:%@",error); }else{ //成功 nslog(@"success %@ %@",response,responseobject); } }]; //启动任务 [uploadtask resume]; }
网络状态:
//网络状态 -(void)demo5{ //1. 创建网络监测者 afnetworkreachabilitymanager *manager = [afnetworkreachabilitymanager sharedmanager]; [manager setreachabilitystatuschangeblock:^(afnetworkreachabilitystatus status) { //监测网络改变 switch (status) { case afnetworkreachabilitystatusunknown: nslog(@"未知网络状态"); break; case afnetworkreachabilitystatusnotreachable: nslog(@"无网络"); break; case afnetworkreachabilitystatusreachableviawwan: nslog(@"蜂窝数据网络"); break; case afnetworkreachabilitystatusreachableviawifi: nslog(@"wifi网络"); break; default: break; } }]; }
本文参考了组长的blog,以及自己学习时整理的一些小demo。
推荐阅读
-
iOS开发中使用NSURLConnection类处理网络请求的方法
-
[日常] 使用TCPDUMP和Ethereal抓包分析HTTP请求中的异常情况
-
apache中使用mod_log_slow分析响应慢的请求
-
iOS中使用schema协议调用APP和使用iframe打开APP的例子分析
-
iOS开发网络篇—发送GET和POST请求(使用NSURLSession) - 转
-
.Net Core 3.0后台使用httpclient请求网络网页和图片_使用Core3.0做一个简单的代理服务器
-
【IOS学习】网络请求中的cookie
-
分析一下iOS网络请求的使用
-
iOS网络请求中常见的几种方式
-
React Native 使用Fetch发送网络请求的示例代码