网络

一、基本知识

  1. 客户端(Client):移动应用(iOS、Android)
  2. 服务器(Server):为客户端提供服务、提供数据、提供资源的机器
  3. 请求(Request):客户端向服务器索要数据的一种行为
  4. 响应(Response):服务器对客户端的请求作出的反应,一般指返回数据给客户端

 二、HTTP基本介绍

  1. 客户端通过URL找到想要连接的服务器。
  2. URL的全称是Uniform Resource Locator(统一资源定位符)
    • URL的基本格式 = 协议://主机地址/路径
    • URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL
    • 协议:不同的协议,代表着不同的资源查找方式、资源传输方式。
    • 主机地址:存放资源的主机(服务器)的IP地址(域名)
    • 路径:资源在主机(服务器)中的具体位置
  3. 常见的协议:HTTP(超文本传输协议)、file(访问本地计算机)、mailto(访问电子邮件)、FTP(访问共享主机的文件资源)。
  4. HTTP协议简介
    • 全称是Hypertext Transfer Protocol,超文本传输协议
    • 规定了客户端和服务器之间的数据传输格式,让客户端和服务器能有效的进行数据沟通。
  5. HTTP协议的特点:
    • 简单快速:因为HTTP协议简单,所以HTTP服务器的程序规模小,因而通信速度很快。
    • 灵活:HTTP允许传输各种各样的数据

三、HTTP请求

  1. 在HTTP/1.1 协议中,定义了8种发送http请求的方法:GET(查)POST(改)、OPTIONS、HEAD、PUT(增)、DELETE(删)、TRACE、CONNECT、PATCH。
  2. 最常用的GET和POST(实际上GET和POST都能够办到增删改查)。 GET请求:
  • 在请求URL后面以?的形式跟上给服务器的参数,多个参数之间用&隔开,比如http://www.test.com/login?username=123&password=123456
  • 由于流浪器和服务器对URL长度有限制,因此在URL后面附带的参数是有限制的,通常不能超过1KB。
POST请求:的熟虑
  • 发给服务器的参数全部都放在请求体中
  • 理论上,POST传递数据是没有限制(具体还得看服务器处理能力)
GET和POST的选择
  • 如果要传递大量的数据,比如文件上传,只能用POST请求。
  • GET的安全性比POST要差些,如果包含机密、敏感信息,建议用POST。
  • 如果仅仅是索取数据(数据的查询),建议使用GET。
  • 如果是增加、修改、删除数据,建议使用POST。

四、iOS中发送HTTP请求的方案

  1. 苹果原生:
    • NSURLConnection:用法简单,最古老最经典最直接的一种方案(坑比较多)。
    • NSURLSession:功能比NSURLConnection更加强大,iOS7开始使用。
    • CFNetwork:NSURL* 的底层,纯C语言。
  2. 第三方框架
    • AFNetworking:简单易用,多人维护迭代。

 五、HTTP通信

  1. HTTP协议规定:一个完整的由客户端发给服务器的HTTP 请求 包含以下内容
    • 请求头:包含了对客户端的环境描述、客户端请求信息等。
      • GET /test.png HTTP/1.1  // 包含了请求方法、请求资源路径、HTTP协议版本
      • Host:168.110.117.36:8081  // 客户端访问的服务器主机地址
      • User-Agent:Mozilla/5.0 // 客户端的类型,客户端的软件环境
      • Accept:text/html,*/* // 客户端所能接收的数据类型
      • Accept-Language:zh-cn // 客户端的语言环境
      • Accept-Encoding:gzip // 客户端支持的数据压缩格式
    • 请求体:客户端发给服务器的具体数据,即参数。
  2. HTTP协议规定:一个完整的HTTP 响应 中包含以下内容
    • 响应头:包含了对服务器的描述、对返回数据的描述
      • HTTP/1.1 200 OK  // 包含了HTTP协议版本、状态码、状态英文名称
      • Server:Apache-Coyote/1.1   // 服务器的类型
      • Content-Type:image、jpeg  // 返回数据类型
      • Data:Mon,23 Jun 2014 12:54:52 GMT // 响应时间
    • 响应体:服务器返回给客户端的具体数据。

六、NSURLConnection

  1. 常用类:
    • NSURLConnetion:负责发送请求,建立客户端和服务器的连接,并收集来自服务器的响应数据。
    • NSURLRequest、NSMutableURLRequest:一个对象代表一个请求,它包含一个NSURL对象、请求方法、请求头、请求体、请求超时时间等。
    • NSURL:请求地址。
  2. 使用步骤:
    • 创建一个NSURL对象,设置请求的路径。
    • 创建NSURLRequest对象,设置请求头和请求体以及请求方法等。(GET请求可以默认不设置请求方法)
    • 使用NSURLConnection发送请求。
  3. 具体使用实例
  • 同步请求

       NSURL *url = [NSURL URLWithString:@"http://news.k618.cn/pic/cnxhy/201504/W020150424355233105959.jpg"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        NSURLResponse *response = nil;
        NSError *error = nil;
        /**
         1.同步请求
         2.此方法9.0之后被弃用
         */
        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        
        UIImage *img = [UIImage imageWithData:data];
        self.imgV.image = img;
  • 异步请求
        NSURL *url = [NSURL URLWithString:@"http://news.k618.cn/pic/cnxhy/201504/W020150424355233105959.jpg"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        
        /**
         1.异步请求
         2.queue: 表示返回block执行与哪个线程中
         2.此方法9.0之后被弃用
         */
        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
            
            // 刷新界面要放在主线程(因为界面的创建就在主线程)
            [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                UIImage *img = [UIImage imageWithData:data];
                self.imgV.image = img;
            }];
            NSLog(@"------data=%@-----response=%@----%@", data, response, [NSThread currentThread]);
        }];
  • 代理请求
    /**
         根据文档可知,delegate运行的环境需要开启了RunLoop,所以,当下列方法放入子线程中时,要开启子线程的RunLoop,否则delegate的方法不会调用。
         */
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        [queue addOperationWithBlock:^{
            
            NSURL *url = [NSURL URLWithString:@"http://t1.mmonly.cc/uploads/tu/zyf/tt/20160316/b3ivxec3bqv.jpg"];
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
            
            NSURLConnection *connetion = [[NSURLConnection alloc] initWithRequest:request delegate:self];
            
            // 可以设置代理方法在哪个线程中执行(暂时设置在主线程,默认主线程)
            [connetion setDelegateQueue:[NSOperationQueue mainQueue]];
            
            [[NSRunLoop currentRunLoop] run]; // 开启子线程的的RunLoop
        }];
    
    #pragma mark - 代理方法
    
    // 开始接收到服务器的响应时调用
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    }
    
    // 接收到服务器返回的数据时调用(服务器返回的数据比较大时会调用多次)
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    }
    
    // 服务器返回的数据完全接收完毕后调用
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    }
    
    // 请求出错时调用(比如请求超时)
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
        NSLog(@"------%s------", __FUNCTION__); 
    }
  • POST和GET请求
    // POST请求 
        NSURL *url = [NSURL URLWithString:[@"http://www.iqiyi.com/v_19rrkowa6k.html?list=19rrmo4fl6" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];;
        
    // 设置请求配置,需要用可变的NSMutableURLRequest设置
        NSMutableURLRequest *mutableRequest = [NSMutableURLRequest requestWithURL:url];
        
        mutableRequest.HTTPMethod = @"POST"; // 设置请求方法,默认为GET请求
        
        mutableRequest.timeoutInterval = 20.0; // 请求超时时间,默认60s
        
        NSString *paramStr = @"list=19rrmo4fl6";
        mutableRequest.HTTPBody = [paramStr dataUsingEncoding:NSUTF8StringEncoding]; // 设置请求体
        
        // 设置请求头
    //    [mutableRequest setValue:<#(nullable NSString *)#> forHTTPHeaderField:<#(nonnull NSString *)#>];
        
        [NSURLConnection sendAsynchronousRequest:mutableRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
            
            NSHTTPURLResponse *re = (NSHTTPURLResponse *)response;
            
            NSLog(@"------response=%@-------statusCode=%d-----", response, re.statusCode);
        }];
    
    // GET请求
    
    NSURL *url = [NSURL URLWithString:[@"http://www.iqiyi.com/v_19rrkowa6k.html?list=19rrmo4fl6" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];;
        
    // 设置请求配置,需要用可变的NSMutableURLRequest设置
        NSMutableURLRequest *mutableRequest = [NSMutableURLRequest requestWithURL:url];
       
        mutableRequest.timeoutInterval = 20.0; // 请求超时时间,默认60s
        
        // 设置请求头
    //    [mutableRequest setValue:<#(nullable NSString *)#> forHTTPHeaderField:<#(nonnull NSString *)#>];
        
        [NSURLConnection sendAsynchronousRequest:mutableRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
            
            NSHTTPURLResponse *re = (NSHTTPURLResponse *)response;
            
            NSLog(@"------response=%@-------statusCode=%d-----", response, re.statusCode);
        }];

七、NSURLSession

  1. 常用类:NSURLSessionTask(抽象类)、NSURLSessionDataTask(一些列请求)、NSURLSessionDownloadTask(下载)、NSURLSessionUploadTask(上传)、NSURLSessionConfiguration(session配置类)。
  2. 使用步骤:
    • 通过NSURLSession创建task
    • 启动task(resume)
  3. 具体实例:
    • 网络请求
      #pragma mark - 代理方法做网络请求
      - (void)urlSessionWithDelegate {
          // 网络请求的的一些配置,例如:超时时间、网络情况等
          NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
          
          // delegateQueue:表示代理方法运行在哪个线程中
          NSURLSession *delegateSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
          
          NSURLSessionDataTask *task = [delegateSession dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://p3.pstatp.com/origin/11fd000255db5f64b772"]]];
          
          [task resume];
      }
      
      #pragma mark - NSURLSessionDataDelegate
      
      // 接收到服务器的响应
      - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
          NSLog(@"-----%s", __FUNCTION__);
          
          // 需要确认以什么样的形式去接收服务器的数据或者不接收。
          completionHandler(NSURLSessionResponseAllow);
          
          _data = [NSMutableData data];
      }
      
      // 接收服务器数据,此方法可能多次调用
      - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
          [_data appendData:data];
          NSLog(@"-----%s---%@", __FUNCTION__, [NSThread currentThread]);
      }
      
      // 网络请求完成
      - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
          
          dispatch_sync(dispatch_get_main_queue(), ^{
              self.imgV.image = [UIImage imageWithData:_data];
          });
          
          NSLog(@"-----%s", __FUNCTION__);
      }
      
      #pragma mark - 快速创建session,做网络请求
      - (void)urlSession {
          // 创建session对象
          NSURLSession *session = [NSURLSession sharedSession];
          
          // 通过session创建task
          NSURLSessionTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://t1.mmonly.cc/uploads/tu/201510/126/1.jpg"]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
              
              dispatch_sync(dispatch_get_main_queue(), ^{
                  self.imgV.image = [UIImage imageWithData:data];
              });
          }];
          
          // 启动task
          [task resume];
      }
    • 下载请求
      #pragma mark - session快速下载
      - (void)downTask {
          NSURLSession *session = [NSURLSession sharedSession];
          NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://p9.pstatp.com/origin/134900068f9a107994f4"]];
          
          // location: 临时文件的位置(*.tmp)
          NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
              
              NSLog(@"--------------%@", location);
              
              NSFileManager *fileManager = [NSFileManager defaultManager];
              
              NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:response.suggestedFilename];
              
              NSURL *destinationURL = [NSURL fileURLWithPath:path];
              
              [fileManager moveItemAtURL:location toURL:destinationURL error:nil];
              
              dispatch_sync(dispatch_get_main_queue(), ^{
                  self.imgV.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:destinationURL]];
              });
              
              NSLog(@"--------------location:%@-------destinationURL:%@-----", location,destinationURL);
          }];
          
          [task resume];
      }
      
      #pragma mark - session代理下载
      - (void)downloadTaskWithDelegate {
          /**
           *  注意点:下载的代理方法中没有response的代理方法,不需要回调去调是否执行接收服务器数据的方法。
           */
          NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
          
          NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
          
          NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"http://p3.pstatp.com/origin/13510001b63985024add"]];
          
          [task resume];
      }
      
      #pragma mark - NSURLSessionDownloadDelegate
      // 接收服务器的下载的数据
      - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
          NSLog(@"---bytesWritten:%ld------totalBytesWritten:%ld------totalBytesExpectedToWrite:%ld------", (long)bytesWritten, (long)totalBytesWritten, (long)totalBytesExpectedToWrite);
          
          [[NSOperationQueue mainQueue] addOperationWithBlock:^{
              self.progressView.progress = (totalBytesWritten / totalBytesExpectedToWrite);
          }];
      }
      
      // 下载的数据接收完毕
      - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
          NSLog(@"---%s", __FUNCTION__);
          
          NSFileManager *fileManager = [NSFileManager defaultManager];
          
          NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
          
          NSURL *destinationURL = [NSURL fileURLWithPath:path];
          
          [fileManager moveItemAtURL:location toURL:destinationURL error:nil];
          
          dispatch_sync(dispatch_get_main_queue(), ^{
              self.imgV.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:destinationURL]];
          });
      }
      
      // 网络请求完成
      - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
          NSLog(@"---%s", __FUNCTION__);
      }
    • 断点下载:断点下载说白了就是下载中途停止了,下次再启动下载。对于此类情形,分两种情况:
      • 在应用内暂定(未关闭应用):这种情况可以直接调用 suspend 的方法暂定下载,再通过resume方法恢复下载。
      • 暂定下载后,退出应用:这种情况,采用 cancelByProducingResumeData:(void (^)(NSData * _Nullable resumeData))completionHandler 方法暂停下载,并本地保存resumeData,再通过 downloadTaskWithResumeData:(NSData *)resumeData 方法恢复下载。
    •    // 方法一:暂停下载(仅适合应用不关闭)
          [_task suspend];
          // 不仅可以启动任务,还可以唤醒suspend状态的任务
          [_task resume];
          
          // 方法二:取消下载,获得恢复记录数据resumeData(保存本地记录)
          [self.task cancelByProducingResumeData:^(NSData *resumeData) {
              self.resumeData = resumeData;
          }];
          // 恢复下载时接过保存的恢复数据
          self.task = [self.session downloadTaskWithResumeData:self.resumeData];
          // 启动任务
          [self.task resume];
      
      // 下载失败时,可以在这方法中获取暂停下载的数据记录resumeData
      - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
      {
          // 保存恢复数据
          self.resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
      }
      
      补充:
          // 取消任务,既可以向resume的状态发送取消任务消息,也可以向suspend的状态发送任务消息,但是此方法一当调用,则下载任务就不能恢复了。
          [_task cancel];
    • 上传
      #pragma mark - 文件上传
      - (void)uploading {
          NSURLSession *session = [NSURLSession sharedSession];
          
          NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:bodydData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
              
          }];
          
          [task resume];
      }
      
      #pragma mark - 代理方法文件上传
      - (void)uploadingWithDelegate {
          /**
           *  1.注意:没有和downloading相似的uploading的代理方法,上传遵循是NSURLSessionDataDelegate代理方法。
           *  2. bodyData: 这上传bodyData比较复杂,大多数人都会采用AFNetworking去解决,具体bodyData的格式请自行百度。
           */
          NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
          NSURLSessionUploadTask *task = [session uploadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.guojinbao.com"]] fromData:bodyData];
          [task resume];
      }
      
      #pragma mark - 上传代理---NSURLSessionDataDelegate
      // 接到服务器的响应
      - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
          NSLog(@"-------%s-----", __FUNCTION__);
      }
      
      // 此方法可以跟踪上传进度,可能多次调用
      - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
         didSendBodyData:(int64_t)bytesSent
          totalBytesSent:(int64_t)totalBytesSent
      totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend {
          NSLog(@"-------%s-----", __FUNCTION__);
      }
      
      // task结束,可能上传成功结束,error为nil,也有可能是上传失败,error有值。
      - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
      didCompleteWithError:(nullable NSError *)error {
          NSLog(@"-------%s-----", __FUNCTION__);
      }
      
      // 其他补充:
      // 这种方法请求,是PUT上传文件,需要服务器支持PUT请求,fileURL:要上传文件的url。(此方法上传不安全)
      - (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request fromFile:(NSURL *)fileURL completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler; 

转载于:https://www.cnblogs.com/shpyoucan/p/6070162.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值