iOS REST Web Service(1)NSURLSession

简述

REST Web Service 是一个使用HTTP并遵循REST原则的Web Service,使用URI来定位资源。Web Service的数据交互格式主要采用JSON和XML等。Web Service所支持的HTTP请求方法包括POST、GET、PUT或DELETE等。

HTTP协议

HTTP是"Hypertext Transfer Protocol"的缩写,超文本传输协议。网络中使用的基本协议是TCP/IP协议,目前被广泛采用的HTTP、HTTPS、FTP、Archie和Gopher等是建立在TCP/IP协议之上的应用层协议,不同的协议对应着不同的应用。
Web Service主要使用HTTP协议,这是一个属于应用层的面向对象的协议,其简洁、快速的方式适用于分布式超文本信息的传输。HTTP协议支持C/S网络结构,是无链接协议,即每一次请求时建立链接,服务器处理完客户端的请求后,应答给客户端,然后断开链接,不会一直占用网络资源。
HTTP/1.1协议定义了8种请求方法:OPTIONS、HEAD、GET、POST、PUT、DELETE、TRACE、CONNECT。GET和POST方法在具体应用中使用比较多。
GET方法是向指定的资源发出请求,发送的信息"显式"地跟在URL后面。GET方法应该只用于读取数据,例如静态图片等。GET方法有点像使用明信片给别人写信,"信内容"卸载外面,接触到的人都可以看到,因此是不安全的。
POST方法是向指定资源提交数据,请求服务器进行处理,例如提交表单或者上传文件等,数据被包含在请求体重。POST方法像是把"信内容"装入信封中,接触到的人看不到,因此是安全的。

HTTPS协议

HTTPS协议是"Hypertext Transfer Protocol Secure"的缩写,超文本传输安全协议,是超文本传输协议和SSL的组合,用来提供加密通信及对网络服务器身份的坚定。
HTTPS是HTTP的升级版,区别是HTTPS使用https;//代替http://,使用端口443,HTTP使用端口80与TCP/IP进行通信。SSL使用40位关键字作为RC4流加密算法,这对于商业信息的加密是合适的HTTPS和SSL支持使用x.509数字认证,可以确认发送者是谁。

苹果ATS限制

iOS9开始,苹果为了提高网络安全,对应用发出的所有网络请求,必须采用HTTPS协议,否则,应用在运行时就会抛出错误。这个限制就是苹果ATS(APP Transport Security)限制。
苹果允许设置ATS白名单(例外名单)。在Xcode工程属性文件info.plist中添加App Transport Security Settings键,ing在该键下面添加Exception Domains键,设置例外的域名,在具体域名下可以添加详细的设置键,如下:
(1)NSIncludesSubdomains,是否包括子域名。
(2)NSExceptionRequiresForwardSecrecy,是否支持正向保密。
(3)NSExceptionAllowsInsecureHTTPLoads,是否允许不安全HTTP加载。
(4)NSExceptionMinimumTLSVersion,设置传输层安全协议最下版本。

NSURLSession

iOS7之后提供的网络通信API,用来代替NSURLConnection网络通信库。NSURKLSession可以为每个用户会话(session)配置缓存、协议和cookie,支持安全证书策略;支持FTP、HTTP和HTTPS等网络协议;支持实现后台下载和上传,以及断点续传功能;还可以取消、恢复、挂起网络请求操作。

NSURLSession API
类:
(1)NSURLSession
(2)NSURLSessionConfiguration
(3)NSURLSessionTask
协议:
(1)NSURLSessionDelegate
(2)NSURLSessionTaskDelegate
(3)NSURLSessionDataDelegate
(4)NSURLSessionDownloadDelegate

会话
会话是指应用程序与服务器建立的通信对象,一个应用程序可以建立多个会话,每个会话协调一组相关的数据传输任务,在NSURLSessionAPI中,会话类是NSURLSession。具体使用时,我们可以创建4种形式的会话:
(1)简单会话,不可配置会话,只能执行基本的网络情况,通过NSURLSession的静态方法+sharedSession获得NSURLSession对象。Swift通过shared静态属性获得对象。
(2)默认会话(default session),与简单会话类似,但是可以配置会话,通过NSURLSession的静态方法+sessionWithConfiguration:或+sessionWithConfiguration:delegate:delegateQueue:获得NSURLSession对象,其中configuration参数是NSURLSessionConfiguration类型,NSURLSessionConfiguration是会话配置类,通过静态方法+defaultSessionConfiguration获得默认会话配置对象。
(3)短暂会话(ephemeral session),不存储任何数据在磁盘中,所有的数据都是缓存的,整数存储等都保存在内存中,当应用结束会话时,他们被自动释放。获得对话对象的方式与默认会话类似,不同的是会话配置对象是通过NSURLSessionConfiguration静态方法+ephemeralSessionConfiguration获得的。
(4)后台会话(background session),当应用程序在后台时,可以在后台执行上传或下载数据任务,获得对话对象的方式与默认会话类似,不同的是会话配置是通过NSURLSessionConfiguration静态方法+backgroundSessionConfigurationWithIdentifier:获得的。

会话任务
会话任务类是NSURLSessionTask,会话3种形式的任务:
(1)数据任务(data task),请求网络资源,从服务器范湖一个或多个NSData对象。数据任务支持简单会话、默认会话和短暂会话,不支持后台会话,数据任务是NSURLSessionDataTask类。
(2)上传任务(upload task),以文件形式发送数据,吃吃后台上传,上传任务是NSURLSessionUploadTask类。
(3)下载任务(download task),以文件形式接收数据,支持后台下载,下载任务是NSURLSessionDownloadTask类。
NSURLSessionTask是一个抽象类,它有NSURLSessionDataTask和NSURLSessionDownloadTask这两个子类,而NSURLSessionUploadTask是NSURLSessionDataTask的子类。
所有任务都可以取消、暂停或恢复。默认情况下,任务是暂停的,所以创建任务后,需要恢复任务才能执行操作。

简单会话实现GET请求

Swift代码

// An highlighted block
class MasterViewController:UITableViewController{
	//保存数据列表
	var listData=NSArray()
	override func viewDidLoad(){
		self.startRequest()
	}
	//开始请求Web Service
	func startRequest(){
		//指定请求的URL
		var strURL=NSSTring(format:"http://www.a.com?email=%@&type=%@","email.qq.com","jsonType")
		//使用NSString的addingPercentEncoding(withAllowedCharacters:)方法将字符串转换为URL字符串。在网上传输时,URL中不能有中文等特殊字符,比如“<”,必须进行URL编码才能传输。方法中的参数是字符集类型CharacterSet,通过静态属性urlQueryAllowed创建一个带有请求参数的URL字符串允许的字符集。
		strURL=strURL.addingPercentEncoding(withAllowedCharacters:CharacterSet.urlQueryAllowed)!
		let url=URL(string:strURL)!
		let request=URLRequest(url:url)
		//用于创建简单会话对象
		let session=URLSession.sharel
		//通过NSURLSession的dataTaskWithRequest:completionHandler:方法获得数据任务(NSURLSessionDataTask)对象,第一个参数是NSURLRequest请求对象,第二个参数completionHandler是请求完成回调的代码块。代码块completionHandler中的data参数是从服务器返回的数据,response是从服务器返回的应答对象,error是错误对象,如果error为nil,则说明请求过程没有错误发生。
		let task:URLSessionDataTask=session.dataTask(with:request,completionHandler:{(data,response,error) in
			print("请求完成")
			if error==nil{
				do{
					let resDict=try JSONSerialization.jsonObject(with:data!,options:JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
					DispatchQueue.main.async(execute:{
						//请求完成调用reloadView:方法
						self.reloadView(resDict)
					}
					)
				}catch{
					print("返回数据解析失败")
				}
			}else{
				print("error:",error!.localizedDescription)
			}
		}
		)
		task.resume()
	}
}

ObjectiveC代码

// An highlighted block
-(void)viewDidLoad{
	[self startRequest];
}
#pragma mark--开始请求Web Service
-(void)startRequest{
	//指定请求的URL
	NSString *strURL=[[NSString alloc] initWithFormat:@"http://www.a.com?email=%@&type=%@",@"email",@"jsonType"];
	//使用NSString的stringByAddingPercentEncodingWithAllowedCharacters:方法将字符串转换为URL字符串。在网上传输时,URL中不能有中文等特殊字符,比如“<”,必须进行URL编码才能传输。方法中的参数是字符集类型NSCharacterSet,通过静态属性URLQueryAllowedCharacterSet创建一个带有请求参数的URL字符串允许的字符集。
	strURL =[strURL stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
	NSURL *url=[NSURL URLWithString:strURL];
	NSURLRequest *request=[[NSURLRequest alloc] initWithURL:url];
	用于创建简单会话对象
	NSURLSession*session=[NSURLSession sharedSession];
	//通过NSURLSession的dataTaskWithRequest:completionHandler:方法获得数据任务(NSURLSessionDataTask)对象,第一个参数是NSURLRequest请求对象,第二个参数completionHandler是请求完成回调的代码块。代码块completionHandler中的data参数是从服务器返回的数据,response是从服务器返回的应答对象,error是错误对象,如果error为nil,则说明请求过程没有错误发生。
	NSURLSessionDataTask *task=[session dataTaskWithRequest:request completionHandler:^(NSData*data,NSURLResponse *response,NSError *error){
		NSLog(@"请求完成");
		if(!error){
			NSDictionary *resDict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
			dispatch_async(dispatch_get_main_queue(),^{
				//请求完成调用reloadView:方法
				[self reloadView:resDict];
			});
		}else{
			NSLog(@"error:%@",error.localizedDescription);
		}
	}];
	[task resume];
}
默认会话实现GET请求

Swift代码

// An highlighted block
//开始请求Web Service
	func startRequest(){
		//指定请求的URL
		var strURL=NSSTring(format:"http://www.a.com?email=%@&type=%@","email.qq.com","jsonType")
		
		strURL=strURL.addingPercentEncoding(withAllowedCharacters:CharacterSet.urlQueryAllowed)!
		let url=URL(string:strURL)!
		let request=URLRequest(url:url)
		//用于创建默认会话对象
		let defaultConfig=URLSessionConfiguration.default
		let session=URLSession(configuration:defaultConfig,delegate:nil,delegateQueue:OperationQueue.main)
		
		let task:URLSessionDataTask=session.dataTask(with:request,completionHandler:{(data,response,error) in
			print("请求完成")
			if error==nil{
				do{
					let resDict=try JSONSerialization.jsonObject(with:data!,options:JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
					//DispatchQueue.main.async(execute:{
						//请求完成调用reloadView:方法
						self.reloadView(resDict)
					//})
				}catch{
					print("返回数据解析失败")
				}
			}else{
				print("error:",error!.localizedDescription)
			}
		})
		task.resume()
	}

ObjectiveC代码

// An highlighted block
#pragma mark--开始请求Web Service
-(void)startRequest{
	//指定请求的URL
	NSString *strURL=[[NSString alloc] initWithFormat:@"http://www.a.com?email=%@&type=%@",@"email",@"jsonType"];
	strURL =[strURL stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
	NSURL *url=[NSURL URLWithString:strURL];
	NSURLRequest *request=[[NSURLRequest alloc] initWithURL:url];
	NSURLSessionConfiguration *defaultConfig=[NSURLSessionConfiguration defaultSessionConfiguration];
	NSURLSession*session=[NSURLSession sessionWithConfiguaration:defaultConfig delegate:nildelegateQueue:[NSOperationQueue mainQueue]];
	
	NSURLSessionDataTask *task=[session dataTaskWithRequest:request completionHandler:^(NSData*data,NSURLResponse *response,NSError *error){
		NSLog(@"请求完成");
		if(!error){
			NSDictionary *resDict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
			//dispatch_async(dispatch_get_main_queue(),^{
				//请求完成调用reloadView:方法
				[self reloadView:resDict];
			//});
		}else{
			NSLog(@"error:%@",error.localizedDescription);
		}
	}];
	[task resume];
}
POST请求

Swift代码

// An highlighted block
func startRequest(){
	//创建一个URL字符串
	let strURL="http://www.a.com"
	let url=URL(string:strURL)!
	let post=NSString(format:"email=%@&type%@","email@1q.com","jsonType")
	//将字符串转换成Data类型,编码一定要采用UTF-8
	let postData:Data=post.data(using:String.Encoding.utf8.rawValue)!
	//用于创建可变的请求对象NSMutableURLRequest,因为是可变的,所以可以通过属性设置其内容
	let mutableURLRequest=NSMutableURLRequest(url:url)
	//设置请求方式
	mutableURLRequest.httpMethod="POST"
	//设置请求参数
	mutableURLRequest.httpBody=postData
	let request=mutableURLRequestas URLRequest
}

ObjectiveC代码

// An highlighted block
-(void)startRequest{
	//创建一个URL字符串
	NSString *strURL=@"http://www.a.com";
	NSURL *url=[NSURL URLWithString:strURL];
	NSString *post=[NSString stringWithFormat:@"email=%@&type=%@",@"email.qqf.com",@"jsonType"];
	//将字符串转换成Data类型,编码一定要采用UTF-8
	NSData *postData=[post dataUsingEncoding:NSUTF8StringEncoding];
	//用于创建可变的请求对象NSMutableURLRequest,因为是可变的,所以可以通过属性设置其内容
	NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
	//设置请求方式
	[request setHTTPMethod:@"POST"];
	//设置请求参数
	[request setHTTPBody:postData];
	NSURLSessionConfiguration *defaultConfig=[NSURLSessionConfiguration defaultSessionConfiguration];
	NSURLSession *session=[NSURLSession sessionWithConfiguration:defaultConfig delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
}
下载数据

在NSURLSession API中,下载数据需要使用下载任务类NSURLSessionDownloadTask实现。三种会话都可以使用,具体采用哪种要看需求而定。例如,在下载过程中向知道下载的进度,或能够支持断点续传,需要实现NSURLSessionDownloadDelegate委托协议来接受服务器回调事件,这个时候不能使用代码块接受服务器回调事件。
例:使用默认会话实现下载。
Swift代码

// An highlighted block
class ViewController:UIViewController,URLSessionDownloadDelegate{
	@IBOutlet weak var progressView:UIProgressView!
	@IBOutlet weak var imageView1:UIImageView!
	@IBOutlet weak var button1:UIButton!
}
@IBAction func onClick(sender:AnyObject){
	//设置下载图片地址
	let strURL=String(format:"http:www.a.com?fileName=%@","test1.jpg")
	let url=URL(string:strURL)!
	let defaultConfig=URLSessionConfiguration.default
	//创建默认会话对象,delegate为self
	let session=URLSession(configuration:defaultConfig,delegate:self,delegateQueue:OperationQueue.main)
	//创建下载会话任务,
	let downloadTask=session.downloadTask(with:url)
	//开始下载
	downloadTask.resume()
}
//实现NSURLSessionDownloadDelegate委托协议
//获得下载进度,bytesWritten:从服务器接收的字节数;totalBytesWritten:累计接收的字节数;totalBytesExpectedToWrite:期待接收的字节数。
func urlSession(_ session:URLSession,downloadTask:URLSessionDownloadTask,didWriteData bytesWritten:Int64,totalBytesWritten:Int64,totalBytesExpectedToWrite:Int64){
	//计算下载进度
	let progress=Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)
	//更新进度条的进度
	self.progressView.setProgress(progress,animated:true)
	NSLog("进度=%f",progress)
	NSLog("接受:%lld字节(已下载:%lld字节)期待:%lld字节.",bytesWritten,totalBytesWritten,totalBytesExpectedToWrite)
}
//下载完成时回调,location参数是下载过程中保存数据的本地临时文件
func urlSession(_ session:URLSession,downloadTask:URLSessionDownloadTask,didFinishDownloadingTo location:URL){
	NSLog("临时文件:%@",location.description)
	let downloadDir=NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,true)[0]
	let downloadStrPat=downloadsDir+"/test1.jpg"
	let downloadURLPath=URL(fileURLWithPath:downloadStrPath)
	let fileManager=FileManager.default
	//判断沙箱Documents目录是否存在test1.jpg文件
	if fileManager.fileExists(atPath:downloadStrPath)==true{
		do{
			try fileManager.removeItem(atPath:downloadStrPath)
		}catch let error as NSError{
			NSLog("删除文件失败:%@",error.locallzedDescription)
		}
	}
	do{
		//将临时存储的文件,移到沙箱Documents目录下,并命名为test1.jpg。
		try fileManager.moveItem(at:location,to:downloadURLPath)
		NSLog("保存文件:%@",downloadStrPath)
		let img=UIImage(contentsOfFile:downloadStrPath)
		self.imageView.image=img
	}catch let error as NSError{
		NSLog("保存文件失败:%@",error.locallzedDescription)
	}
}

ObjectiveC代码

// An highlighted block
//ViewController.m文件
#import "ViewController.h"
@interface ViewController()<NSURLSessionDownloadDelegate>
@property(week,nonatomic)IBOutlet UIProgressView *progressView;
@property(week,nonatomic)IBOutlet UIImageView *imageView1;
@property(week,nonatomic)IBOutlet UIButton *button1;
@end
@implementation ViewController
-(IBAction)onClick:(id)sender{
	//设置下载图片地址
	NSString *strURL=[[NSString alloc] initWithFormate:@"http://www.a.com?fileName=%@",@"test1.jpg"];
	NSURL *url=[NSURL NSURLWithString:strURL];
	NSURLSessionConfiguration *defaultConfig=[NSURLSessionConfiguration defaultSessionConfiguration];
	//创建默认会话对象,delegate为self
	NSURLSession *session=[NSURLSession sessionWithConfiguration:defaultConfig delegate:self delegateQueue:[NSOprationQueue mainQueue]];
	//创建下载会话任务,
	NSURLSessionDownloadTask *downloadTask=[session downloadTaskWithURL:url];
	//开始下载
	[downloadTask resume];
}
#pragma mark --实现NSURLSessionDownloadDelegate委托协议
-(void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
	float progress=totalBytesWritten*1.0/totalBytesExpectedToWrite;
	[self.progressViewsetProgress:progress animated:TRUE];
	NSLog(@"进度=%f",progress);
	NSLog("接受:%lld字节(已下载:%lld字节)期待:%lld字节.",bytesWritten,totalBytesWritten,totalBytesExpectedToWrite);
}
//下载完成时回调,location参数是下载过程中保存数据的本地临时文件
-(void)URLSession:(NSURLSession*)session downloadTask:(NSURLSessionDownloadTask*)downloadTask didFinishDownloadingToURL:(NSURL*)location{
	NSLog("临时文件:%@",location);
	NSString *downloadsDir=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,TRUE) objectAtIndex:0 ];
	NSString *downloadStrPath=[downloadsDir stringByAppendingPathComponent:@"/test1.jpg"];
	NSURL*downloadURLPath=[NSURLfileURLWithPath:downloadStrPath];
	NSFileManage *fileManager=[NSFileManager defaultManager];
	NSError *error=nil;
	//判断沙箱Documents目录是否存在test1.jpg文件
	if([fileManager fileExistsAtPath:downloadStrPath]){
		//删除test1.jpg文件
		[fileManager removeItemAtPath:downloadStrPath error:&error];
		if(error){
			NSLog(@"删除文件失败:%@",error.localizedDescription);
		}
	}
	error=nil;
	//将临时存储的文件,移到沙箱Documents目录下,并命名为test1.jpg。
	if([fileManager moveItemAtURL:location toURL:downloadURLPath error:&error]){
		NSLog(@"文件保存:%@",downloadStrPath);
		UIImage *img=[UIImage imageWithContentsOfFile:downloadStrPath];
		self.imageView1.image=img;
	}else{
		NSLog(@"保存文件失败:%@",error.localizedDescription);
	}
}
@end

参考资料
《IOS开发指南 从HELLO WORLD到APP STORE上架 第5版》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值