网络请求
之前也说过了, 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 9
和Mac OS 10.11
开始, 苹果爸爸就想把所有网络请求都全部改为HTTPS
(RFC 2818), 但由于一下子转变肯定是不太可能的, 所以就有一个名为ATS
的安全特性.
在新建项目里面, 我们会发没法正常的发送HTTP
请求, 这就是ATS
搞的鬼, 我们需要在工程里面设置一下, 详细怎么设置去找度娘吧.
如果你想了解更多的资料, 那就去苹果爸爸的官方文档看看Information Property List Key Reference中的NSAppTransportSecurity.