zoukankan      html  css  js  c++  java
  • 网络

    一、基本知识

    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都能够办到增删改查)。
    3. GET请求:
      • 在请求URL后面以?的形式跟上给服务器的参数,多个参数之间用&隔开,比如http://www.test.com/login?username=123&password=123456
      • 由于流浪器和服务器对URL长度有限制,因此在URL后面附带的参数是有限制的,通常不能超过1KB。
      POST请求:的熟虑
      • 发给服务器的参数全部都放在请求体中
      • 理论上,POST传递数据是没有限制(具体还得看服务器处理能力)
    4. 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; 
    此文章为个人笔记,方便自己以及有需要的朋友查看,转载请注明出处!
  • 相关阅读:
    线性回归的从零开始实现
    比赛总结
    计数学习笔记
    DP计数问题
    多项式学习笔记
    数据结构学习笔记
    子集运算学习笔记
    待学习
    ICPC2018焦作 题解
    ICPC2018焦作 H题 Can You Solve the Harder Problem?
  • 原文地址:https://www.cnblogs.com/shpyoucan/p/6070162.html
Copyright © 2011-2022 走看看