ios原生API文件上传(NSURLSession)

一、 简介

以前,在上传文件时,可以使用NSURLConnection类,由于这个类已经过期,只支持到ios9, 所以,本节使用NSURLSession来上传文件。

NSURLSession针对下载/上传等复杂的网络操作提供了专门的解决方案,针对普通、上传和下载分别对应三种不同的网络请求任务:NSURLSessionDataTask, NSURLSessionUploadTask和NSURLSessionDownloadTask 。创建的task都是挂起状态,需要resume才能执行。

二、使用

1、引入框架和定义编码宏

1
2
3
#import <MobileCoreServices/MobileCoreServices.h>

#define GMEncode(str) [str dataUsingEncoding:NSUTF8StringEncoding]

2、编写上传方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-(void)upload:(NSString *)filePath params:(NSDictionary *)params{
NSURL *url = [NSURL URLWithString:@"http://192.168.1.103:9088/up/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];

//分隔符
NSString *boundary = [self generateBoundaryString];

//设置ContentType
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];

//获取body体数据
NSString *fieldName = @"CustomFile";
NSData *bodyData = [self createBodyWithBoundary:boundary parameters:params filePath:filePath fieldName:fieldName];

NSURLSessionTask *task = [[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:bodyData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (error) {
NSLog(@"error : %@", error);
return;
}
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"上传返回结果 : %@", result);
}];

[task resume];
}

3、body体拼接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
- (NSData *)createBodyWithBoundary:(NSString *)boundary
parameters:(NSDictionary *)parameters
filePath:(NSString *)filePath
fieldName:(NSString *)fieldName {
//创建可变Data
NSMutableData *bodyData = [NSMutableData data];

//文本参数
[parameters enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL * _Nonnull stop) {
//开始
NSString *startStr = [NSString stringWithFormat:@"--%@\r\n",boundary];
[bodyData appendData:GMEncode(startStr)];

//描述
NSString *dispositionStr = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key];
[bodyData appendData:GMEncode(dispositionStr)];

//值
NSString *valueStr = [NSString stringWithFormat:@"%@\r\n", obj];
[bodyData appendData:GMEncode(valueStr)];
}];

//文件
NSString *fileName = [filePath lastPathComponent];
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSString *mimetype = [self mimeTypeForPath:filePath];

//文件分割
NSString *fileBoundaryStr = [NSString stringWithFormat:@"--%@\r\n",boundary];
[bodyData appendData:GMEncode(fileBoundaryStr)];

//文件描述
NSString *fileDispositionStr = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, fileName];
[bodyData appendData:GMEncode(fileDispositionStr)];

//类型
NSString *contentTypeStr = [NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype];
[bodyData appendData:GMEncode(contentTypeStr)];

//文件NSData
[bodyData appendData:data];

//换行
[bodyData appendData:GMEncode(@"\r\n")];

//结尾
NSString *endStr = [NSString stringWithFormat:@"--%@--\r\n",boundary];
[bodyData appendData:GMEncode(endStr)];

return bodyData;
}

4、获取mimeType

1
2
3
4
5
6
7
8
9
10
///根据文件路径获取mimeType
- (NSString *)mimeTypeForPath:(NSString *)path {
CFStringRef extension = (__bridge CFStringRef)[path pathExtension];
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);
NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType));

CFRelease(UTI);

return mimetype;
}

5、生成分隔符字符串

1
2
3
- (NSString *)generateBoundaryString {
return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
}