美文网首页
iOS NSURLSession 讲解 (二)

iOS NSURLSession 讲解 (二)

作者: 奔跑吧小蚂蚁 | 来源:发表于2018-07-04 16:58 被阅读74次

    网络请求

    之前也说过了, NSURLSession本身是不会进行网络请求的, 那如果我们要用GET或者是POST请求咋搞呢? 直接来看代码吧:

    GET请求:

     // 获取共享的单例Session对象
        NSURLSession *urlSession = [NSURLSession sharedSession];
        
        // 请求的URL地址, 我这里拿百度图片的, 而且这里我并没有兼容HTTP, 要兼容HTTP请求的, 可以到工程项目里配置
        NSURL *url = [NSURL URLWithString:@"https://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=%E5%9B%BE%E7%89%87"];
        
        // 通过上面的URL地址来创建NSURLSessionDataTask对象, 并且在completionHandler:打印一下所获取到的Data数据
        NSURLSessionDataTask *dataTask = [urlSession dataTaskWithURL:url
                                                   completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                       
                                                       NSLog(@"请求的数据为: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
                                                   }];
        
        // 开始执行任务
        [dataTask resume];
    

    POST请求:

     // 获取共享的单例Session对象
        NSURLSession *urlSession = [NSURLSession sharedSession];
        
        // 创建一个NSURL对象
        NSURL *url = [NSURL URLWithString:@"https://image.baidu.com/search/index?"];
        
        // 创建一个NSMutableURLRequest对象, 并设置HTTPMethod的请求方式和HTTPBody的请求内容.
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
        
        urlRequest.HTTPMethod = @"POST";
        urlRequest.HTTPBody   = [@"tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=%E5%9B%BE%E7%89%87" dataUsingEncoding:NSUTF8StringEncoding];
        
        // 通过NSURLRequest对象创建一个NSURLSessionDataTask, 并在completionHandler:回调方法里NSLog一下我们所请求到的数据.
        NSURLSessionDataTask *dataTask = [urlSession dataTaskWithRequest:urlRequest
                                                       completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
                                                           NSLog(@"请求的数据为: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
                                                       }];
        
        // 开始执行任务
        [dataTask resume];
    
    

    上传文件

    刚刚我们简单的讲了一下GET和POST这两种常用的请求方式, 现在我们来看看上传文件的方法, 上传也有几种方法, 我们一个个来看看:

    根据指定的本地文件地址来上传:

     // 创建一个NSURLRequest对象, 注意, 这里要有一个明确的上传地址, 不然你要往哪里上传咧?
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"上传地址"]];
       
        // 本地文件的NSURL
        NSURL *fileURL = [NSURL URLWithString:@"本地文件地址"];
        
        // 通过NSURLRequest对象来创建一个NSURLSessionUploadTask, 配置好File的URL, 还可以在completionHandler: 回调里看看我们是否成功上传.
        NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                        fromFile:fileURL
                                                                               completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                                                   
                                                                                   NSLog(@"上传信息: %@", [NSJSONSerialization JSONObjectWithData:data
                                                                                                                                      options:kNilOptions
                                                                                                                                        error:nil]);
                                                   }];
        
        // 开始执行任务
        [uploadTask resume];
    
    

    根据指定的NSData对象来上传:

    // 创建一个NSURLRequest对象
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"上传地址"]];
        
        // 创建一个NSData对象, 这里我就不详细写了, 因为我没有可以上传的服务器
        NSData *fileData = [NSData data];
        
        // 通过NSURLRequest对象来创建一个NSURLSessionUploadTask, 配置好NSData对象, 还可以在completionHandler: 回调里看看我们是否成功上传.
        NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                        fromData:fileData
                                                                               completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                                                   
                                                                                   NSLog(@"上传信息: %@", [NSJSONSerialization JSONObjectWithData:data
                                                                                                                                      options:kNilOptions
                                                                                                                                        error:nil]);
                                                                        }];
                                                                        
        // 执行任务
        [uploadTask resume];
    

    以数据流的方式去上传, 老司机们都说这种方式挺不错的, 因为好处就是大小不限制.

    // 初始化一个上传地址
        NSString *urlString = @"上传地址";
        
        // 如果在上传的的URL地址出现特殊字符的话, 我们这里就要做一下特殊处理
        urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
        
        NSURL *url = [NSURL URLWithString:urlString];
        
        // 创建一个NSMutableURLRequest对象
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
        
        // 网络请求方式设置为POST
        urlRequest.HTTPMethod = @"POST";
        
        // 创建一个NSData对象, 并且设置好上传文件的地址
        NSData *fileData = [NSData dataWithContentsOfFile:@"文件的路径"];
        
        // 通过指定的URLRequest和FildData来创建NSURLSessionUploadTask, 并且可以在completionHandler:方法里获取是否上传成功
        NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                        fromData:fileData
                                                                               completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
                                                                                   if (error) {
                                                                                       
                                                                                       NSLog(@"上传发生了错误: %@", error);
                                                                                       
                                                                                       return;
                                                                                   }
                                                                                   
                                                                                   NSLog(@"上传你成功:%@",[[NSString alloc] initWithData:data
                                                                                                                           encoding:NSUTF8StringEncoding]);
                                                                               }];
        
        // 执行任务
        [uploadTask resume];
    

    使用表单方式来进行上传, 这里我们需要先自定义两个方法:

    // 传入文件的路径, 文件名, 上传的需要更改的文件名
    - (NSData *)getHTTPBodyWithFilePath:(NSString *)filePath
                               fileName:(NSString *)fileName
                               restName:(NSString *)restName {
        
        NSMutableData *data = [NSMutableData data];
        
        NSURLResponse *response = [self getLocalFileResponse:filePath];
        
        // 文件类型:MIMEType  文件的大小:expectedContentLength  文件名字:suggestedFilename
        NSString *fileType = response.MIMEType;
        
        // 如果没有传入上传后文件名称,采用本地文件名!
        if (restName == nil) {
            restName = response.suggestedFilename;
        }
        
        // 表单拼接
        NSMutableString *headerString =[NSMutableString string];
        
        [headerString appendFormat:@"--%@\r\n",@"boundary"];
        
        // name:表单控件名称  filename:上传文件名
        [headerString appendFormat:@"Content-Disposition: form-data; name=%@; filename=%@\r\n", fileName, restName];
        [headerString appendFormat:@"Content-Type: %@\r\n\r\n",fileType];
        
        [data appendData:[headerString dataUsingEncoding:NSUTF8StringEncoding]];
        
        // 文件内容
        NSData *fileData = [NSData dataWithContentsOfFile:filePath];
        
        [data appendData:fileData];
        
        NSMutableString *footerStrM = [NSMutableString stringWithFormat:@"\r\n--%@--\r\n",@"boundary"];
        
        [data appendData:[footerStrM  dataUsingEncoding:NSUTF8StringEncoding]];
        
        NSLog(@"dataStr=%@",[[NSString alloc] initWithData:data
                                                  encoding:NSUTF8StringEncoding]);
        
        return data;
    }
    
    /// 获取响应,主要是文件类型和文件名
    - (NSURLResponse *)getLocalFileResponse:(NSString *)urlString {
        
        urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
        
        // 本地文件请求
        NSURL *url = [NSURL fileURLWithPath:urlString];
        
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        
        __block NSURLResponse *localResponse = nil;
        
        // 使用信号量实现NSURLSession同步请求
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        
        [[[NSURLSession sharedSession] dataTaskWithRequest:request
                                         completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                             
                                             localResponse = response;
                                             
                                             dispatch_semaphore_signal(semaphore);
                                             
                                         }] resume];
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        return  localResponse;
    }
    

    现在我们就来开始拼接表单, 并且上传文件:

    // 初始化一个上传地址
        NSString *urlString = @"上传地址";
        
        // 如果在上传的的URL地址出现特殊字符的话, 我们这里就要做一下特殊处理
        urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
        
        NSURL *url = [NSURL URLWithString:urlString];
        
        // 创建一个NSMutableURLRequest对象
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
        
        // 网络请求方式设置为POST
        urlRequest.HTTPMethod = @"POST";
        
        NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", @"boundary"];
        
        [urlRequest setValue:contentType
          forHTTPHeaderField:@"Content-Type"];
        
        // 创建一个NSData对象, 并且设置好上传文件的地址
        NSData *fileData = [self getHTTPBodyWithFilePath:@"/Users/lifengfeng/Desktop/test.jpg"
                                                fileName:@"file"
                                                restName:@"newName.png"];
        
        urlRequest.HTTPBody = fileData;
        
        [urlRequest setValue:[NSString stringWithFormat:@"%lu", fileData.length]
          forHTTPHeaderField:@"Content-Length"];
        
        // 通过指定的URLRequest来创建NSURLSessionUploadTask, 并且可以在completionHandler:方法里获取是否上传成功, 由于我们在URLRequest已经添加了Data数据, 所以这里的FileData可以忽略不理
        NSURLSessionUploadTask *uploadTask = [[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest
                                                                                        fromData:nil
                                                                               completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            
                                                                                   if (error) {
                                                                                       
                                                                                       NSLog(@"上传发生了错误: %@", error);
                                                                                       
                                                                                       return;
                                                                                   }
                                                                                   
                                                                                   NSLog(@"上传你成功:%@",[[NSString alloc] initWithData:data
                                                                                                                           encoding:NSUTF8StringEncoding]);
                                                                               }];
        
        // 执行任务
        [uploadTask resume];
    

    下载文件

    NSURLSessionDownloadTask也是我们常用到的Task, 这里就说说怎么用来下载文件吧:

    // 创建一个文件下载的地址
        NSString *urlString = @"文件下载地址";
        
        // 处理特殊的字符
        urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        
        NSURL *url = [NSURL URLWithString:urlString];
        
        
        NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
        
        NSURLSession *urlSession = [NSURLSession sharedSession];
        
        NSURLSessionDownloadTask *downloadTask = [urlSession downloadTaskWithRequest:urlRequest
                                                                   completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                                       
                                                                       if(error) {
                                                                           
                                                                           NSLog(@"download error:%@",error);
                                                                           
                                                                           return;
                                                                       }
                                                                       
                                                                       //location:下载任务完成之后,文件存储的位置,这个路径默认是在tmp文件夹下!
                                                                       //只会临时保存,因此需要将其另存
                                                                       
                                                                       NSLog(@"location:%@", location.path);
                                                                       
                                                                       //如果你是用模拟器测试,为了方便可以将保存路径设置为Mac桌面
                                                                       // NSString *filePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
                                                                       
                                                                       NSString *filePath = @"文件的保存地址";
                                                                       
                                                                       NSError *fileError;
                                                                       
                                                                       [[NSFileManager defaultManager] copyItemAtPath:location.path
                                                                                                               toPath:filePath
                                                                                                                error:&fileError];
                                                                       
                                                                       if(fileError){
                                                                           
                                                                           NSLog(@"file save error: %@",fileError);
                                                                       } else {
                                                                           
                                                                           NSLog(@"file save success");
                                                                       }
                                                                   }];
    
        // 开始下载
        [downloadTask resume];
    

    APP的传输安全(ATS)

    iOS 9Mac OS 10.11开始, 苹果爸爸就想把所有网络请求都全部改为HTTPS(RFC 2818), 但由于一下子转变肯定是不太可能的, 所以就有一个名为ATS的安全特性.

    在新建项目里面, 我们会发没法正常的发送HTTP请求, 这就是ATS搞的鬼, 我们需要在工程里面设置一下, 详细怎么设置去找度娘吧.

    如果你想了解更多的资料, 那就去苹果爸爸的官方文档看看Information Property List Key Reference中的NSAppTransportSecurity.

    相关文章

      网友评论

          本文标题:iOS NSURLSession 讲解 (二)

          本文链接:https://www.haomeiwen.com/subject/nwtyuftx.html