NSURLConnection
一. iOS中发送HTTP请求的方案
-
苹果原生
- NSURLConnection: 用法简单, 比较古老但是最直接的方案
- NSURLSession: 功能比NSURLConnection强大, 苹果目前推荐使用的技术(2013年推出, iOS7开始的技术)
- CFNetwork: NSURL类型框架的底层实现, 纯C语言
-
第三方框架
- ASIHttpRequest: 外号HTTP终结者, 功能及其强大, 但是已经停止更新
- AFNetworking: 简单易用, 提供了大部分常用的功能, 维护使用者多
- MKNetworkKit: 简单易用, 印度阿三的产物, 使用者维护者较少
-
建议
- 随着AFN框架的普遍性以及众多开发者合力维护, 建议尽量使用AFN框架
- 并且, 为了提高开发效率, 建议直接使用三方框架
二. NSURLConnection发送GET请求
-
常用类的介绍
- iOS中与网络相关的类, 都是以NSURL开头的类
- NSURLRequest: 请求类, 每一个Request对象就代表一个请求, 其中包含的信息大致有:
- NSURL对象, 代表请求的URL地址
- 请求方法, 请求头, 请求体
- 请求超时的信息(通过代理方法来监听)
- 是否允许蜂窝移动网络发送请求等等....
- NSMutableURLRequest: 他是NSURLRequest的子类, 可以在请求的同时包含更多的详细属性参数, 多用于POST请求
- NSURLConnection: 负责处理网络交互的类
- 负责发送请求, 建立客户端和服务器连接的类
- 发送数据给服务器, 并收集来自服务器的响应数据
-
NSURLConnection的使用步骤
- 创建一个NSURL对象, 也就是设置请求路径
- 使用NSURL对象来创建一个NSURLRequest对象, 并且设置请求头, 请求体
- 使用NSURLConnection发送请求(发送请求的常见方式如下)
- 同步请求:
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
- 异步请求(不会卡住主线程): 根据对服务器返回数据的处理方式不同, 可分为两种
- block回调:
+ (void)sendAsynchronousRequest:(NSURLRequest*) request queue:(NSOperationQueue*) queue completionHandler:(void (^)(NSURLResponse* response, NSData* data, NSError* connectionError)) handler
- 代理监听请求结果: 注意遵守协议
- 首先, 要在发送请求的同时设置代理:
+ (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate
- 之后, 如果使用的是代理方法, 那么就需要手动发出网络请求
- (void)start
- 最后, 可以通过各种代理方法来处理返回的数据
- 首先, 要在发送请求的同时设置代理:
- block回调:
- 同步请求:
-
GET请求的代码示例:
// 同步请求 - (void)sendSync { // 1. 请求路径 NSURL *url = [NSURL URLWithString:@"http://192.168.1.101:88/login?username=MyiOS&pwd=999&type=JSON"]; // 2. 创建请求对象 // requeset内部会自动提供默认的请求头信息,默认是以GET方式发送的 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 3. 发送请求 // 3.1 响应头,他和响应体都是以data数据返回的 NSURLResponse *response = nil; // 3.2 发送请求获取数据 NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil]; NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); // 4. 打印响应头 NSLog(@"%@", response); NSLog(@"%@", [NSThread currentThread]); // 在主线程解析数据 } // 异步请求 - block回调 - (void)sendAsync { // 1. 请求路径 NSURL *url = [NSURL URLWithString:@"http://192.168.1.101:88/login?username=MyiOS&pwd=999&type=JSON"]; // 2. 创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 3. 发送异步请求 /* (NSURLRequest *)request 请求对象 (NSOperationQueue *)queue 队列(决定代码在哪个线程中执行) completionHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *connectionError))handler 连接完成后回调 NSURLResponse *response 响应头信息 NSData *data 返回的数据 NSError *connectionError 如果请求失败,保存失败信息 */ [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { // 3.1 如果连接错误为nil,证明连接成功 if (connectionError == nil) { // 4. 解析返回的数据 NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); NSLog(@"%@", response); NSLog(@"%@", [NSThread currentThread]); // 在子线程中解析数据 } }]; NSLog(@"%@", [NSThread currentThread]); } // 异步请求2 - 代理监听 - (void)sendAsync2 { // 1. 创建请求路径 NSURL *url = [NSURL URLWithString:@"http://192.168.1.101:88/login?username=MyiOS&pwd=999&type=JSON"]; // 2. 创建请求对象 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 3. 设置代理,发送请求 NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; // 4. 开始发送网络请求 [connection start]; } #pragma mark - 代理方法,当发送了请求之后,会调用的方法 // 1. 当接收到了响应的时候调用 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { // 当接收到了响应,就创建data对象,准备接收数据 self.data = [NSMutableData data]; NSLog(@"%@", response); } // 2. 当接收到了数据的时候调用 /* 1> 该方法可能调用多次,当返回数据较大的时候,系统会一点一点接收数据 2> 把每次接收的数据拼接起来,等接收完成,就是完整的数据了 */ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // 查看当前数据的长度 NSLog(@"%ld", data.length); // 拼接数据 [self.data appendData:data]; } // 3. 当请求失败的时候调用该方法 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"请求失败"); } // 4. 当请求完成的时候调用,请求已经完成,接收数据完毕 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { // 解析数据 NSLog(@"%@", [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding]); NSLog(@"数据接收完毕"); NSLog(@"%@", [NSThread currentThread]); }
三. NSURLConnection发送POST请求
-
NSMutableURLRequest
- 普通的NSURLRequest默认发送的是GET请求, GET只能发送一些简单的请求, 用于获取数据
- 而NSMutableURLRequest, 可以包含更多的请求信息, 如:
- 修改请求方法: 默认的请求方式为GET
- 设置最大请求时间: 当超过最大时间还没连接成功的话, 那么认为请求失败
- 设置请求头信息: 比如设置客户端的信息(当前设备为iOS9.0)
- 设置请求体: 请求体是将NSData的二进制数据, 发送给服务器, 通过这点就可以发送文件
- 补充GET和POST的请求格式
- GET: http://192.168.2.101:40/login?username=MyiOS&pwd=999&type=JSON
- POST: http://192.168.2.101:40/lgoin
- 从上可以看出, GET在?之后, 将参数一同发送给了服务器
- 而POST则是将参数单独抽取出来, 放在Request对象中发送
-
POST请求的简单实现代码
- (void)post { // 1. 确定请求路径 NSURL *url = [NSURL URLWithString:@"http://192.168.2.101:40/lgoin"]; // 2. 创建可变请求对象 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 3. 修改请求方法为POST(因为默认为GET) request.HTTPMethod = @"POST"; // 4. 设置最大请求时间 request.timeoutInterval = 15; // 如果请求时间超过15秒还没得到响应,那么认为请求失败 // 5. 设置请求头信息(Key为User-Agent) [request setValue:@"iOS 9.0" forHTTPHeaderField:@"User-Agent"]; // 6. 设置请求体(将参数发送给服务器) request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding]; // 7. 发送请求(异步) [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { // 接收数据并解析 if (connectionError == nil) { NSLog(@"数据接收完毕,开始解析"); NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); } }]; }
-
补充:
- 如果你的系统版本是适配iOS7.0以后的版本, 尽量使用NSURLSession
- 同时, 在企业开发中, 尽量使用AFN等三方框架来处理你的网络请求, 提高开发效率