NSURLSession笔记(二)上传文件

NSURLSession系列笔记:
NSURLSession笔记 文件下载

总体思路和NSURLConnection上传文件是相似的,而且并不会比NSURLConnection方便多少,以前写过的一篇NSURLConnection上传文件的笔记会写得更详细,这里就简单说一下NSURLSession的上传,毕竟它们的流程大致相同的。NSURLConnection笔记-上传文件

  • “不正确”的上传方式,使用dataTask。
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}] resume];

普通网络任务一般不用来做上传或者下载,但尽管如此,如果用来上传、小文件的下载的话还是能够实现的。

  • 正确的上传方式,使用uploadTask,主要有一下两种:
NSURLSessionUploadTask *dataTask=[[NSURLSession sharedSession] uploadTaskWithRequest:request fromFile:fileName completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
   }];
NSURLSessionUploadTask *dataTask=[[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:bodyData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
   }];

Session会自动计算Header的Content-length。通常,还需要提供一些服务器需要的Header,Content-Type就往往需要提供。

上传文件:

 // 1. 创建请求   
NSURL *url = [NSURL URLWithString:@"xxxurl"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];    

request.HTTPMethod = @"POST";    
// 设置请求头,告诉服务器本次长传的时文件信息 // 这一块的内容是不变的!
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",bound];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
    
// 设置请求体,拼接文件传输格式
NSMutableString *bodyHeaderStr = [NSMutableString stringWithFormat:@"--%@\r\n",bound];
[bodyHeaderStr appendFormat:@"Content-Disposition: form-data; name=%@; filename=%@\r\n",@"userfile",@"JSON"];
[bodyHeaderStr appendString:@"Content-Type: application/octet-stream\r\n\r\n"];//两个换行
NSData *fileData = [NSData dataWithContentsOfFile:@"本地文件路径"];  
NSMutableString *bodyFooterStr = [NSMutableString stringWithFormat:@"\r\n--%@--",bound];
      //拼接成二进制数据
NSMutableData *bodyData = [NSMutableData data];
[bodyData appendData:[bodyHeaderStr dataUsingEncoding:NSUTF8StringEncoding]];
[bodyData appendData:fileData];
[bodyData appendData:[bodyFooterStr dataUsingEncoding:NSUTF8StringEncoding]];

//request.HTTPBody = bodyData ;
    
// 2. 发送请求
[[[NSURLSession sharedSession] uploadTaskWithRequest:request fromData: bodyData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}] resume];

后来用新浪微博的API来做了一下授权发布带图片的微博,上传图片。
这里的 access_token 大家可以用自己的微博来测试 access_token->是通过自己的微博账号密码生成的 具体流程可以参照 http://www.cnblogs.com/ok-lanyan/archive/2012/07/15/2592070.html 以及官方api文档来做就好了

- (IBAction)uploadPic:(id)sender {
    //1.构建URL
    NSURL *url=[NSURL URLWithString:@"https://api.weibo.com/2/statuses/upload.json"];
    //2.创建request请求
    //NSURLRequest 不可变的 NSMutableURLRequest可变的 可以设置请求属性
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    
    [request setHTTPMethod:@"POST"];
    [request setTimeoutInterval:120];
    [request setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
    
    //请求头//upload task不会在请求头里添加content-type(上传数据类型)字段
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; charset=utf-8;boundary=%@", boundary];
    [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
    //设置请求体
    //发送的微博需要这2个参数
    //access_token(微博令牌,根据用户名,密码生成的明文密码) status(微博内容)
    //pic (图片) ----因为图片转成字符串编码量太大如果直接拼接在URL里服务器无法识别其请求,所以要把图片数据放在请求体里
    
    //本地图片
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"桌面.jpg" ofType:nil];
    //拼接请求体
    NSData *bodyData=[self setBodydata:filePath];//(注意上面宏定义的请求体边界下面就要用上了)
    
    //3.创建网络会话
    NSURLSession *session=[NSURLSession sharedSession];
    //4.创建网络上传任务
    NSURLSessionUploadTask *dataTask=[session uploadTaskWithRequest:request fromData:bodyData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error == nil) {
            
            NSLog(@"%@",response);//202及是发布成功
            NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:data  options:NSJSONReadingMutableLeaves error:nil];
                    NSLog(@"jsonDic:%@",jsonDic);
                    NSLog(@"original_pic:%@",[jsonDic objectForKey:@"original_pic"]);
        };
    }];
    
    //5.发送网络任务
    [dataTask resume];
    
    
    //————————————————————————————POST请求体格式——————————————————————————————
    //这个格式比较繁琐,但是这是死格式,大家耐心看,就可以看出规律了。注意看红字分析
    
    //---->拼接成字符串,然后转成 NSData 返回
    
    /*
     HTTP请求头:
     ....
     multipart/form-data; charset=utf-8;boundary=AaB03x //上传数据类型 必须要设置其类型
     ....
     
     
     HTTP请求体:
     
     --AaB03x (边界到下一行用了换行,在oc里面 用 \r\n 来定义换一行 所以下面不要奇怪它的用法)
     Content-Disposition: form-data; name="key1"(这行到 value1 换了2行,所以,自然而然 \r\n\r\n )
     
     value1
     --AaB03x
     Content-disposition: form-data; name="key2"
     
     value2
     --AaB03x
     Content-disposition: form-data; name="key3"; filename="file"
     Content-Type: application/octet-stream
     
     图片数据...//NSData
     --AaB03x--(结束的分割线也不要落下)
     */
}

- (NSData *)setBodydata:(NSString *)filePath
{
    //把文件转换为NSData
    NSData *fileData = [NSData dataWithContentsOfFile:filePath];
    
    //1.构造body string
    NSMutableString *bodyString = [[NSMutableString alloc] init];
    
    //2.拼接body string
    //(1)access_token
    [bodyString appendFormat:@"--%@\r\n", boundary];//(一开始的 --也不能忽略)
    [bodyString appendFormat:@"Content-Disposition: form-data; name=\"access_token\"\r\n\r\n"];
    [bodyString appendFormat:@"2.00cDQNuBJKVJQC6c99b892efwRBlYB\r\n"];
    
    //(2)status
    [bodyString appendFormat:@"--%@\r\n", boundary];
    [bodyString appendFormat:@"Content-Disposition: form-data; name=\"status\"\r\n\r\n"];
    [bodyString appendFormat:@"带图片的微博\r\n"];
    
    //(3)pic
    [bodyString appendFormat:@"--%@\r\n", boundary];
    [bodyString appendFormat:@"Content-Disposition: form-data; name=\"pic\"; filename=\"file\"\r\n"];
    [bodyString appendFormat:@"Content-Type: application/octet-stream\r\n\r\n"];
    
    
    //3.string --> data
    NSMutableData *bodyData = [NSMutableData data];
    //拼接的过程
    //前面的bodyString, 其他参数
    [bodyData appendData:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
    //图片数据
    [bodyData appendData:fileData];
    //4.结束的分隔线
    NSString *endStr = [NSString stringWithFormat:@"\r\n--%@--\r\n",boundary];
    //拼接到bodyData最后面
    [bodyData appendData:[endStr dataUsingEncoding:NSUTF8StringEncoding]];
    return bodyData;
}

ps:uploadTask没有对应的uploadDelegate,但是NSURLSessionDataDelegate,NSURLSessionDelegate,NSURLSessionTaskDelegate同样适用于UploadTask
比如:-(void)URLSession: task: didSendBodyData: totalBytesSent: totalBytesExpectedToSend:获取上传进度

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

推荐阅读更多精彩内容