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.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_X自主阅读 15,979评论 3 119
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,392评论 1 92
  • 10.1今天开始我要把每次旅行都记录下来哦。这次十一去的是大连,丹东,盘锦,从连云港出发。坐了半天车,半天船,终于到了。
    小屁猪阅读 142评论 0 0
  • 麻屋子 红帐子 里面住个白胖子
    一个麻麻阅读 291评论 0 0
  • 今天是个好日子,经过两个周的考量和准备,五年级七班学生作品专栏开栏啦!看,孩子们涌到专栏前驻足欣赏,脸上满...
    枫叶常华阅读 853评论 11 8