iOS学习笔记12

您所在的位置:网站首页 put请求干什么用的 iOS学习笔记12

iOS学习笔记12

2023-01-23 04:07| 来源: 网络整理| 查看: 265

一、网络请求 在网络开发中,需要了解一些常用的请求方法: GET请求:get是获取数据的意思,数据以明文在URL中传递,受限于URL长度,所以传输数据量比较小。 POST请求:post是向服务器提交数据的意思,提交的数据以实际内容形式存放到消息头中进行传递,无法在浏览器url中查看到,大小没有限制。 HEAD请求:请求头信息,并不返回请求数据体,而只返回请求头信息,常用用于在文件下载中取得文件大小、类型等信息。 Web请求 二、NSURLConnection

NSURLConnection是苹果提供的原生网络访问类,但是苹果很快会将其废弃,且由NSURLSession(iOS7以后)来替代。目前使用最广泛的第三方网络框架AFNetworking最新版本已弃用了NSURLConnection,那我们学习它还有什么用呢?

首先,苹果弃用它还是需要时间的,最起码到iOS10之后。 现在还有一些老项目会使用NSURLConnection,特别是2013年之前的项目,用户量基础还是很大的; 另外,不得不承认,有些公司还在用类似ASI这些经典的网络框架,所以还是很有必要学习NSURLConnection的。

让我们来首先了解几个类:

1. NSURL:请求地址,定义一个网络资源路径 NSURL *url = [NSURL URLWithString:@"协议://主机地址/路径?参数&参数"]; 解释如下: 协议:不同的协议,代表着不同的资源查找方式、资源传输方式,比如常用的http,ftp等 主机地址:存放资源的主机的IP地址(域名) 路径:资源在主机中的具体位置 参数:参数可有可无,也可以多个。如果带参数的话,用“?”号后面接参数,多个参数的话之间用&隔开 2.NSURLRequest:请求,根据前面的NSURL建立一个请求 NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0]; 参数解释如下: url:资源路径 cachePolicy:缓存策略(无论使用哪种缓存策略,都会在本地缓存数据),类型为枚举类型,取值如下: NSURLRequestUseProtocolCachePolicy = 0 //默认的缓存策略,使用协议的缓存策略 NSURLRequestReloadIgnoringLocalCacheData = 1 //每次都从网络加载 NSURLRequestReturnCacheDataElseLoad = 2 //返回缓存否则加载,很少使用 NSURLRequestReturnCacheDataDontLoad = 3 //只返回缓存,没有也不加载,很少使用 timeoutInterval:超时时长,默认60s 另外,还可以设置其它一些信息,比如请求头,请求体等等,如下: NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0]; // 告诉服务器数据为json类型 [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; // 设置请求体body(json类型的数据) NSData *jsonData = [NSJSONSerialization dataWithJSONObject:@{@"userid":@"123456"} options:NSJSONWritingPrettyPrinted error:nil]; request.HTTPBody = jsonData;

注意,上面的request是NSMutableURLRequest,即可变类型

3.NSURLResponse:请求结果响应,连接成功后服务器会返回的响应 该类不用我们创建,连接后服务器返回的,里面包含了一些响应信息 下面我们来发个完整的网络请求: #pragma mark 发送数据请求 - (void)sendRequest{ NSString *urlStr = [NSString stringWithFormat:@"http://192.168.1.208/FileDownload.aspx?file=%@",_textField.text]; //注意对于url中的中文是无法解析的,需要进行url编码(指定编码类型为utf-8) //另外注意url解码使用stringByRemovingPercentEncoding方法 urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //创建url链接,该链接是下载文件 NSURL *url = [NSURL URLWithString:urlStr]; //创建请求 NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0f]; //创建连接,设置请求,以及设置代理 NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; //启动连接,用start启动的连接都是异步请求 [connection start]; } 要得到请求的数据,需要实现NSURLConnection的代理方法: #pragma mark - 连接代理方法 #pragma mark 开始响应 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ _data = [[NSMutableData alloc] init]; _progressView.progress = 0; //通过响应头中的Content-Length取得整个响应的总长度 NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; NSDictionary *httpResponseHeaderFields = [httpResponse allHeaderFields]; _totalLength = [[httpResponseHeaderFields objectForKey:@"Content-Length"] longLongValue]; } #pragma mark 接收响应数据(根据响应内容的大小此方法会被重复调用) - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ //连续接收数据 [_data appendData:data]; //更新进度 [self updateProgress]; } #pragma mark 数据接收完成 - (void)connectionDidFinishLoading:(NSURLConnection *)connection{ //数据接收完保存文件(注意苹果官方要求:下载数据只能保存在缓存目录) NSString *savePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; savePath = [savePath stringByAppendingPathComponent:_textField.text]; [_data writeToFile:savePath atomically:YES]; } #pragma mark 请求失败 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ //如果连接超时或者连接地址错误可能就会报错 } 网络请求下载

但这样每次都要去实现这些代理,感觉十分麻烦,不用怕,NSURLConnection有简化方法,这也是我们用的最多得。

typedef void (^CompletionBlock)(NSURLResponse*, NSData*, NSError*); /* 发送一个异步请求 */ + (void)sendAsynchronousRequest:(NSURLRequest *)request /*请求*/ queue:(NSOperationQueue *)queue /* 连接所在线程队列 */ completionHandler:(CompletionBlock)completion;/* 请求回调 */ /* 发送一个同步请求 */ + (void)sendSynchronousRequest:(NSURLRequest *)request /*请求*/ queue:(NSOperationQueue *)queue /* 连接所在线程队列 */ completionHandler:(CompletionBlock)completion;/* 请求回调 */ 这样我们就不用实现代理方法了,下面是简化方法的使用实例: #pragma mark 发送数据请求 - (void)sendRequest{ NSString *urlStr = [NSString stringWithFormat:@"%@",kURL]; urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //创建url链接 NSURL *url = [NSURL URLWithString:urlStr]; /*创建可变请求*/ NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:5.0f]; [requestM setHTTPMethod:@"POST"];//设置位post请求 //创建post参数 NSString *bodyDataStr = [NSString stringWithFormat:@"userName=%@&password=%@",_userName,_password]; NSData *bodyData = [bodyDataStr dataUsingEncoding:NSUTF8StringEncoding]; [requestM setHTTPBody:bodyData]; //发送一个异步请求 [NSURLConnection sendAsynchronousRequest:requestM queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { if (!error) { //加载数据 [self loadData:data]; //刷新表格 [_tableView reloadData]; } }]; } 三、进阶-文件分段下载

实际开发文件下载的时候,不管是通过代理方法还是静态方法执行请求和响应,我们都会分批请求数据,而不是一次性请求数据。

假设一个文件有1G,那么只要每次请求1M的数据,请求1024次也就下载完了。那么如何让服务器每次只返回1M的数据呢? 在网络开发中可以在请求的头文件中设置一个range信息,它代表请求数据的大小。 在WEB开发中我们还有另一种请求方法“HEAD”,通过这种请求服务器只会响应头信息,其他数据不会返回给客户端,这样一来整个数据的大小也就可以得到了。 首先我们需要先获取要下载的文件大小: #pragma mark 取得文件大小 - (long long)getFileTotlaLength:(NSString *)fileName{ NSURL *url = [self getDownloadUrl:fileName];//获取URL,这个方法我就不列出来了 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0f]; //设置为头信息请求 [request setHTTPMethod:@"HEAD"]; NSURLResponse *response; NSError *error; //注意这里使用了同步请求,直接将文件大小返回 [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; //取得内容长度 return response.expectedContentLength; } 我们还需要封装一个下载指定数据大小的请求: #pragma mark 下载指定块大小的数据 - (void)downloadFile:(NSString *)fileName startByte:(long long)start endByte:(long long)end{ NSString *range = [NSString stringWithFormat:@"Bytes=%lld-%lld",start,end]; NSURL *url = [self getDownloadUrl:fileName]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0f]; //通过请求头设置数据请求范围 [request setValue:range forHTTPHeaderField:@"Range"]; NSURLResponse *response = nil; NSError *error = nil; //注意这里使用同步请求,避免文件块追加顺序错误 NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; if(!error){ [self fileAppend:[self getSavePath:fileName] data:data]; } } 最后我们来下载整个文件: #pragma mark 异步下载文件 - (void)downloadFileAsync{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self downloadFile]; }); } #pragma mark 文件下载,拼接每个下载小文件 - (void)downloadFile{ // 获取要下载的文件总大小 _totalLength = [self getFileTotlaLength:_textField.text]; _loadedLength = 0; long long startSize = 0; long long endSize = 0; //分段下载 while(startSize < _totalLength){ //kFILE_BLOCK_SIZE 宏定义的是分段下载的字节大小 endSize = startSize + kFILE_BLOCK_SIZE - 1; if (endSize > _totalLength) { endSize = _totalLength - 1; } [self downloadFile:_textField.text startByte:startSize endByte:endSize]; //更新进度 _loadedLength += (endSize - startSize) + 1; [self updateProgress]; startSize += kFILE_BLOCK_SIZE; } } 分段下载 四、进阶-文件上传

要实现文件上传,需要采用POST请求,请求数据类型必须为multipart/form-data

我们常见得请求数据类型有: application/x-www-form-urlencoded:默认值,发送前对所有发送数据进行url编码,支持浏览器访问,通常文本内容提交常用这种方式。 multipart/form-data:多部分表单数据,支持浏览器访问,不进行任何编码,通常用于文件传输(此时传递的是二进制数据) 。 text/plain:普通文本数据类型,支持浏览器访问,发送前其中的空格替换为“+”,但是不对特殊字符编码。 application/json:json数据类型 。 text/xml:xml数据类型。

我们需要自己定制上传请求,以下为定制过程:

1. 上传请求头必须满足如下格式: 上传请求头 2. 请求体内容要求如下面格式: --boundary Content-Disposition:form-data;name=”表单控件名称”;filename=”上传文件名称” Content-Type:文件MIME Types 文件二进制数据; --boundary-- 上传请求体 至于上面上传文件的MIME Types类型,我列出几个常用的: *.gif文件 - image/gif *.html文件 - text/html *.jpg文件 - image/jpeg *.mov文件 - video/quicktime *.mp3文件 - audio/mpeg *.pdf文件 - application/pdf *.txt文件 - text/plain *.xml文件 - text/xml *.avi文件 - video/x-msvideo 下面为上传文件具体实例: #pragma mark 上传文件 -(void)uploadFile{ NSString *fileName = _textField.text; NSURL *url = [self getUploadUrl:fileName]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0f]; request.HTTPMethod = @"POST"; NSData *data = [self getHttpBody:fileName]; //通过请求头设置 NSString *lengthStr = [NSString stringWithFormat:@"%lu",(unsigned long)data.length]; [request setValue:lengthStr forHTTPHeaderField:@"Content-Length"]; NSString *typeStr = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",kBOUNDARY_STRING]; [request setValue:typeStr forHTTPHeaderField:@"Content-Type"]; //设置数据体 request.HTTPBody = data; //发送异步请求 [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { if(error){ NSLog(@"error:%@",connectionError.localizedDescription); } }]; } #pragma mark 取得数据体 -(NSData *)getHttpBody:(NSString *)fileName{ NSMutableData *dataM = [NSMutableData data]; NSString *type = [self getMIMETypes:fileName]; //构建请求体body的顶部 NSMutableString *bodyTop = [NSMutableString string]; //宏kBOUNDARY_STRING就是boundary标示 [bodyTop appendFormat:@"--%@\n",kBOUNDARY_STRING]; [bodyTop appendFormat:@"Content-Disposition: form-data; name=\"file1\"; filename=\"%@\"\n",fileName]; [bodyTop appendFormat:@"Content-Type: %@\n\n",type]; //构建请求体body的底部 NSString *bodyBottom = [NSString stringWithFormat:@"\n--%@--",kBOUNDARY_STRING]; NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:nil]; //构建请求体body中间的二进制上传数据 NSData *fileData = [NSData dataWithContentsOfFile:filePath]; //把顶部、数据、底部组合起来,形成body [dataM appendData:[bodyTop dataUsingEncoding:NSUTF8StringEncoding]]; [dataM appendData:fileData]; [dataM appendData:[bodyBottom dataUsingEncoding:NSUTF8StringEncoding]]; return dataM; } 有什么问题随时可以在下方评论提出!O(∩_∩)O哈!


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3