People Lack Willpower,Rather Than Strength!
客户端和服务器之间如何通信?
-
简而言之:
- 客户端和服务器之间通信,由于使用不同语言编程,所以使用HTTP协议,完成双方数据交流;客户端以HTTP方式发送请求,服务器做出响应;
-
常见请求发送方式:
- NSURLConnection;
- NSURLSession;
- AFNetworking;
-
发送请求步骤:
// NSURLConnection: 1.创建url; 2.根据url创建request; 3.使用NSURLConnection发送request;
HTTP
- HTTP协议中向服务器发送请求的方法有多种,我们开发中常用的有get/post;
- 1.get:处理纯粹获得资源的请求,同时,参数不能太大,不超过1KB;
- 2.post:处理需要保密(简单保密),参数较大的请求
NSURLConnection
-
发送请求步骤:
// NSURLConnection: 1.创建url; 2.根据url创建request; 3.使用NSURLConnection发送request;
-
发送请求方式:
- NSURLConnection中提供发送request的方案:
1.sendSync....:主线程中进行,比较耗时,会阻塞; 2.sendAsync...:在子线程中进行,可惜不能监控服务器返回的响应体中的data进度 3.initWithRequest.....可以做到...监控进度,且是子线程. 或者:connectionWithRequest....
- NSURLRequest
- 用于保存请求地址/请求头/请求体
- 默认情况下NSURLRequest会自动给我们设置好请求头
- request默认情况下就是GET请求
登录请求
- get方法-------NSURLRequest同步/异步方法发送请求:
/*=======================get同步方法发送request================================*/
- (void)sendSync
{
// NSURLConnection-->http采用get请求|sendSync...方案发送请求
// 1.创建URL
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
// 2.创建request
// 默认情况下NSURLRequest会自动给我们设置好请求头
// request默认情况下就是GET请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.发送request
/*
第一个参数:需要请求的对象;
第二个参数:服务返回给我们的响应头信息;
第三个参数:错误信息;
返回值:服务器返回给我们的响应体
*/
// NSURLResponse *response = nil;
// response的真实类型是:
NSHTTPURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
// 打印响应头/体信息
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
NSLog(@"%@",response.allHeaderFields);
NSLog(@"touches...即将结束-------");
/*
2015-09-07 09:19:32.287 01-NSURLConnection基本使用[1116:143990] {"success":"登录成功"}
2015-09-07 09:19:32.287 01-NSURLConnection基本使用[1116:143990] {
"Content-Type" = "application/json;charset=UTF-8";
Date = "Mon, 07 Sep 2015 01:19:29 GMT";
Server = "Apache-Coyote/1.1";
"Transfer-Encoding" = Identity;
}
2015-09-07 09:19:32.287 01-NSURLConnection基本使用[1116:143990] touches...即将结束-----
*/
}
/*============================get 异步方法发送request======================*/
- (void)sendAsync
{
// 异步方法发送request
// 1.创建URL
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];
// 2.创建request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 3.异步发送request
/*
参数说明:
参数一:需要请求的对象;
参数二:回调block的队列,决定了block在哪个线程中执行;
参数三:回调block(响应体句柄)
*/
// 注意:如果这里是同步,会阻塞当前线程
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
/*
response:响应头;
data:响应体;
connectionError:错误信息;
*/
NSLog(@"%@",request.HTTPBody);
NSLog(@"%@",request.allHTTPHeaderFields);
/*
2015-09-07 09:59:20.422 01-NSURLConnection基本使用[1425:362793] (null)
2015-09-07 09:59:20.423 01-NSURLConnection基本使用[1425:362793] (null)
为啥是NULL??😖
*/
NSLog(@"%@",response);
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
NSLog(@"touches...即将结束-------");
/*
2015-09-07 09:15:42.689 01-NSURLConnection基本使用[1075:121037] touches...即将结束-------
2015-09-07 09:15:42.731 01-NSURLConnection基本使用[1075:121037] <NSThread: 0x7fd649d19e20>{number = 1, name = main}
2015-09-07 09:15:42.731 01-NSURLConnection基本使用[1075:121037] {"success":"登录成功"}
*/
}
-
登录请求:请求头/体
-
post方法发送请求,这里以异步为例:
// POST方法:可监控数据接收进度 // 1.创建URL NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"]; // 2.创建request-->请求需要是可变类型 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 设置请求方式 request.HTTPMethod = @"POST"; // 这里一定要大写 // httpbody:NSData类型 // 注意: 如果是给POST请求传递参数: 那么不需要写?号,?只是get方法中参数与地址的分隔符! request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding]; // 3.发送请求 [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); }];
-
中文问题
- 说明:
默认情况下,get方法,需要转码;
-
默认情况下,post方法,不需要转码,因为参数放在请求体中,而且是以二进制形式:
request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
-
开发中,考虑可能出错,一律转码.
// get方法中的中文转码: - (void)get_sendAsync { // 请求中的中文问题 // get方法--->要先转码❤️ // 1.url NSString *urlStr = @"http://120.25.226.186:32812/login2?username=小码哥&pwd=520it&type=JSON"; // 转码前 NSLog(@"转码前---%@",urlStr); urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSLog(@"转码后---%@",urlStr); NSURL *url = [NSURL URLWithString:urlStr]; // 2.request NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 3.sendAsync [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); }]; /* 可见:get方法发送请求时,参数中不能有中文,需要转码 2015-09-07 11:41:06.128 03-URL中文问题[2576:823835] 转码前---http://120.25.226.186:32812/login2?username=小码哥&pwd=520it&type=JSON 2015-09-07 11:41:06.128 03-URL中文问题[2576:823835] 转码后---http://120.25.226.186:32812/login2?username=%E5%B0%8F%E7%A0%81%E5%93%A5&pwd=520it&type=JSON 2015-09-07 11:41:06.201 03-URL中文问题[2576:823835] {"success":"登录成功"} */ } //======================================================= // post方法--->无需转码❤️ // 实际开发中,无论get/post都进行转码,省的更改. // 1.url NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login2"]; // 2.request NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"POST"; // 这里将参数转换为二进制data,无需再转码!❤️ request.HTTPBody = [@"username=小码哥&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding]; // type可以不写 // 3.sendAsync [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); }];
- 说明:
下载请求
-
说明:
- 由于我们需要对下载过程进行监控,所以这里我们需要对NSURLConnection对象设置代理!
-
下载请求步骤:
- 1.url创建;
- 2.request创建;
- 3.创建connection,设置代理,执行request;
- 4.实现代理方法;
-
示例:
-
1.request
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 通过initWithRequest.../connection方法发送请求,可以监控数据下载进度 // 1.URL创建---->下载请求❤️ NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"]; // 2.request创建 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 3.发送请求 // NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest:request delegate:self]; // [NSURLConnection connectionWithRequest:request delegate:self]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; // 如果startImmediately:NO,则需要手动开启发动请求 [connection start]; // NSLog(@"%@",connect); /* <NSURLConnection: 0x7f83c0716c70> { request: <NSURLRequest: 0x7f83c0745600> { URL: http://120.25.226.186:32812/resources/images/minion_02.png } } // 可见这里不是我们想要下载的东西,可以不写 */ }
-
2.代理方法
// --------------------------------代理方法---------------------------- #pragma mark - NSURLConnectionDataDelegate // 只要接收到服务器的响应就会调用 // response:响应头 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { // NSLog(@"%s", func); // 在此处,我们可以获得服务器返回给我们的文件总大小 self.totalLength = response.expectedContentLength; // response中包含的属性含义: // 收到数据建议名字 NSLog(@"%@",response.suggestedFilename); // 服务器响应数据大小 NSLog(@"%lld",response.expectedContentLength); // 请求url NSLog(@"%@",response.URL); // 数据类型 NSLog(@"%@",response.MIMEType); // 2015-09-07 11:06:40.240 02-NSURLConnection其他用法[2140:690910] minion_02.png // 2015-09-07 11:06:40.241 02-NSURLConnection其他用法[2140:690910] 43852 // 2015-09-07 11:06:40.241 02-NSURLConnection其他用法[2140:690910] http://120.25.226.186:32812/resources/images/minion_02.png // 2015-09-07 11:06:40.241 02-NSURLConnection其他用法[2140:690910] image/png NSLog(@"%@",response); // 可见此处response包含两大部分内容:1.请求url;2.响应头; // 2015-09-07 10:59:48.113 02-NSURLConnection其他用法[1975:661374] <NSHTTPURLResponse: 0x7feadb7d5940> { URL: http://120.25.226.186:32812/resources/images/minion_02.png } { status code: 200, headers { // "Accept-Ranges" = bytes; // "Content-Length" = 43852; // "Content-Type" = "image/png"; // Date = "Mon, 07 Sep 2015 02:42:51 GMT"; // Etag = "W/\"43852-1409456092000\""; // "Last-Modified" = "Sun, 31 Aug 2014 03:34:52 GMT"; // Server = "Apache-Coyote/1.1"; // } } } // 接收到服务器返回的数据时调用(该方法可能调用一次,或者多次) // data:服务器返回的数据(是当前一次返回的,不是累积量) - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // NSLog(@"%s", func); self.currentLength += data.length; NSLog(@"%f",1.0 * self.currentLength / self.totalLength); } // 数据下载完成时调用 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { // NSLog(@"%s", func); self.currentLength = 0; } // 请求错误时调用(请求超时) /* connection:didFailWithError: will be called at most once, if an error occurs during a resource load. No other callbacks will be made after.<p> */ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { // NSLog(@"%s", func); } /* 可见:服务器响应:响应头--->响应体-->下载完成 2015-09-07 10:57:22.590 02-NSURLConnection其他用法[1939:649504] -[ViewController connection:didReceiveResponse:] 2015-09-07 10:57:22.591 02-NSURLConnection其他用法[1939:649504] -[ViewController connection:didReceiveData:] 2015-09-07 10:57:22.591 02-NSURLConnection其他用法[1939:649504] -[ViewController connectionDidFinishLoading:] */
-