iOS-原生网络请求(详细说明)

技 术 文 章 / 超 人


GET,POST基本带参数网络请求

   //请求地址
    NSURL *url = [NSURL URLWithString:URLString];
    
    //设置请求地址
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //设置请求方式
    request.HTTPMethod = @"POST";
    
    //设置请求参数
    request.HTTPBody = [parameters dataUsingEncoding:NSUTF8StringEncoding];
  //关于parameters是NSDictionary拼接后的NSString.关于拼接看后面拼接方法说明
    
    
    //设置请求session
    NSURLSession *session = [NSURLSession sharedSession];
    
    //设置网络请求的返回接收器
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (error) {
                if (failure) {
                    failure(error);
                }
            }else
            {
                NSError *error;
                NSMutableDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
                if (error) {
                    if (failure) {
                        failure(error);
                    }
                }else
                {
                    if (success) {
                        success(responseObject);
                    }
                }
            } 
        });
    }];
//开始请求
    [dataTask resume];

拼接parameters 参数

/**
 拼接字典数据

 @param parameters 参数
 @return 拼接后的字符串
 */
-(NSString *)parameters:(NSDictionary *)parameters
{
    //创建可变字符串来承载拼接后的参数
    NSMutableString *parameterString = [NSMutableString new];
    //获取parameters中所有的key
    NSArray *parameterArray = parameters.allKeys;
    for (int i = 0;i < parameterArray.count;i++) {
    //根据key取出所有的value
        id value = parameters[parameterArray[i]];
    //把parameters的key 和 value进行拼接
        NSString *keyValue = [NSString stringWithFormat:@"%@=%@",parameterArray[i],value];
        if (i == parameterArray.count || i == 0) {
        //如果当前参数是最后或者第一个参数就直接拼接到字符串后面,因为第一个参数和最后一个参数不需要加 “&”符号来标识拼接的参数
            [parameterString appendString:keyValue];
        }else
        {
        //拼接参数, &表示与前面的参数拼接
            [parameterString appendString:[NSString stringWithFormat:@"&%@",keyValue]];
        }
    }
    return parameterString;
}

上传文件原生请求

NSURLRequestCachePolicy 缓存枚举说明

//指定缓存逻辑。URL加载系统提供了一个磁盘和内存混合的缓存,来相应网络请求。这个缓存允许一个应用减少对网络连接的依赖,并且增加性能。使用缓存的目的是为了使用的应用程序能更快速的响应用户输入,是程序高效的运行。有时候我们需要将远程web服务器获取的数据缓存起来,减少对同一个url多次请求。
typedef NS_ENUM(NSUInteger, NSURLRequestCachePolicy)
{
    NSURLRequestUseProtocolCachePolicy = 0,//默认缓存策略。具体工作:如果一个NSCachedURLResponse对于请求并不存在,数据将会从源端获取。如果请求拥有一个缓存的响应,那么URL加载系统会检查这个响应来决定,如果它指定内容必须重新生效的话。假如内容必须重新生效,将建立一个连向源端的连接来查看内容是否发生变化。假如内容没有变化,那么响应就从本地缓存返回数据。如果内容变化了,那么数据将从源端获取

    NSURLRequestReloadIgnoringLocalCacheData = 1,// URL应该加载源端数据,不使用本地缓存数据

    NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4, // 本地缓存数据、代理和其他中介都要忽视他们的缓存,直接加载源数据

    NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData,//两个的设置相同

    NSURLRequestReturnCacheDataElseLoad = 2,//使用缓存数据,忽略其过期时间;只有在没有缓存版本的时候才从源端加载数据。
    NSURLRequestReturnCacheDataDontLoad = 3,//只使用cache数据,如果不存在cache,请求失败;用于没有建立网络连接离线模式

    NSURLRequestReloadRevalidatingCacheData = 5, //指定如果已存的缓存数据被提供它的源段确认为有效则允许使用缓存数据响应请求,否则从源段加载数据。
};
//只有响应http和https的请求会被缓存。ftp和文件协议当被缓存策略允许的时候尝试接入源段。自定义的NSURLProtocol类能够保护缓存,如果它们被选择使用的话。

mimeType 文件类型

iOS-原生网络请求(详细说明)_第1张图片
image.png

上传文件请求

//指定NSMutableURLRequest的 url请求地址、缓存机制、超时时长
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URLString]
                                                           cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                       timeoutInterval: self.timeoutInterval];

    //指定加载进度的回调
    self.progressBlock = upProgress;
    
    /*
      multipart/from-data 编码类型,以提高二进制文件的传输效率。是一种进行表单提交时的消息格式。表单提交数据的时候,默认类型是application/x-www-form-urlencoded,也就是key=value的键值对格式,提交文件的时候使用multipart/from-data。因为是表单提交,所以http请求方式是POST。然后在请求头里设置Content-Type为multipart/from-data指定请求的格式
      charset=utf-8 编码格式
      boundary 分隔符,分隔多个文件、表单项。确保整个分隔符不会在文件或表单项的内容中出现。
    */
    //设置HTTPHeader中Content-Type的值
    [request setValue:[[NSString alloc] initWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@",self.boundary] forHTTPHeaderField:@"Content-Type"];

    //请求方式
    request.HTTPMethod = @"POST";
    
    /*
     parameters 请求参数
     fileData 上传的文件 NSData类型
     name 文件名,一般随意取或与服务器协商
     fileName 文件加后缀名,例如传图片  就取  test.jpg 一般随意取或与服务器协商
      mimeType 文件类型
    */
   //该方法拼接上传文件的 Data数据
    NSData * payloadData = [self setBodydataWithParameters:parameters fileData:fileData name:name fileName:fileName mimeType:mimeType];

    /* 1、defaultSessionConfiguration"返回标准配置,这实际上与NSURLConnection的网络协议栈是一样的,具有相同的共享NSHTTPCookieStorage,共享NSURLCache和共享NSURLCredentialStorage。
  2、 "ephemeralSessionConfiguration"返回一个预设配置,没有持久性存储的缓存,Cookie或证书。这对于实现像"秘密浏览"功能的功能来说,是很理想的。
  3、 "backgroundSessionConfiguration":独特之处在于,它会创建一个后台会话。后台会话不同于常规的,普通的会话,它甚至可以在应用程序挂起,退出,崩溃的情况下运行上传和下载任务。初始化时指定的标识符,被用于向任何可能在进程外恢复后台传输的守护进程提供上下文。
    * /
    //NSURLSessionConfiguration对象用于初始化NSURLSession对象
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];

    //如果要使用代理方法,需要设置代理,但从NSURLSession的头文件发现session的delegate属性是只读的.因此设置代理要通过session的初始化方法赋,delegateQueue参数表示协议方法将会在哪个队列(NSOperationQueue)里面执行.
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
    
    
    
    NSURLSessionUploadTask * uploadtask = [session uploadTaskWithRequest:request fromData:payloadData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (!error) {
                NSError *jserror = nil;
                NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jserror];
                if (jserror) {
                    if (failure){
                        failure(jserror);
                    }
                }else if (success) {
                    success(dic);
                }
            }else if (failure){
                failure(error);
            }
        });
        
    }];
    //开始请求
    [uploadtask resume];

上传文件Data拼接方法

/**
 文件Data拼接

 @param parameter 上传参数
 @param data 文件源
 @param name 文件名
 @param fileName 文件加后缀的具体名称
 @param mimeType 文件类型
 @return 拼接后的Data
 */
- (NSData *)setBodydataWithParameters:(NSDictionary *)parameter
                             fileData:(NSData *)data
                                 name:(NSString *)name
                             fileName:(NSString *)fileName
                             mimeType:(NSString *)mimeType
{
    
    NSData * imageData = data;
    //1.构造body string
    NSMutableString *bodyString = [[NSMutableString alloc] init];
    
    //2.拼接body string
    NSMutableData *bodyData = [NSMutableData data];
    [parameter enumerateKeysAndObjectsUsingBlock:^(NSString *  _Nonnull key, NSString *  _Nonnull obj, BOOL * _Nonnull stop) {
        [bodyString appendFormat:@"--%@\r\n", self.boundary];
        [bodyString appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
        [bodyString appendFormat:@"%@\r\n",obj];
    }];
    
    [bodyString appendFormat:@"--%@\r\n", self.boundary];
    [bodyString appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",name,fileName];
    [bodyString appendFormat:@"Content-Type: %@\r\n\r\n",mimeType];
    
    //拼接的过程
    //前面的bodyString, 其他参数
    [bodyData appendData:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
    //图片数据
    [bodyData appendData:imageData];
    
    //4.结束的分隔线
    NSString *endStr = [NSString stringWithFormat:@"\r\n--%@--\r\n",self.boundary];
    //拼接到bodyData最后面
    [bodyData appendData:[endStr dataUsingEncoding:NSUTF8StringEncoding]];
    
    return bodyData;
}

关于NSURLSessionDelegate

上传进度获取

/*
 调用该方法上传文件数据
 如果文件数据很大,那么该方法会被调用多次
 参数说明:
     totalBytesSent:已经上传的文件数据的大小
     totalBytesExpectedToSend:文件的总大小
 */
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
    
    self.uploadProgress.totalUnitCount = totalBytesExpectedToSend;
    self.uploadProgress.completedUnitCount = totalBytesSent;
    //这里的progressBlock、uploadProgress都是自己定义的回调。上面上传文件中也有设置
    self.progressBlock(self.uploadProgress) ;
}

参考资料:
1.NSURLSession使用说明及后台工作流程分析
2.iOS开发之网络编程--6、NSURLSessionConfiguration笔记
3.使用NSURLSession

你可能感兴趣的:(iOS-原生网络请求(详细说明))