iOS NSURLSession 讲解 (二)

网络请求

之前也说过了, 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 讲解 (二))