iOS网络编程

2018-11-05  本文已影响3人  CoderRH

一、URL

  • URL的全称是Uniform Resource Locator(统一资源定位符),通过1个URL,能找到互联网上唯一的1个资源,URL就是资源的地址、位置,互联网上的每个资源都有一个唯一的URL

  • 的基本格式 = 协议://主机地址/路径,示例:
    http://www.baidu.com/img/logo.png
    http://111.111.111.111/img/bdlogo.gif

  • 协议、主机地址、路径的含义:
    协议:不同的协议,代表着不同的资源查找方式、资源传输方式
    主机地址:存放资源的主机(服务器)的IP地址(域名)
    路径:资源在主机(服务器)中的具体位置

二、HTTP协议

1.HTTP协议简介
  • HTTP的全称是Hypertext Transfer Protocol,超文本传输协议
  • 规定客户端和服务器之间的数据传输格式
  • 让客户端和服务器能有效地进行数据沟通
2.HTTP协议特点
  • 简单快速:因为HTTP协议简单,所以HTTP服务器的程序规模小,因而通信速度很快
  • 灵活:HTTP允许传输各种各样的数据
  • HTTP 0.9和1.0使用非持续连接:限制每次连接只处理一个请求,服务器对客户端的请求做出响应后,马上断开连接,这种方式可以节省传输时间
3.HTTP协议的请求方法
  • 在HTTP/1.1协议中,定义了8种发送http请求的方法:GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE、CONNECT、PATCH
  • PUT :增、DELETE :删、POST:改、GET:查
  • 最常用的是GET和POST(实际上GET和POST都能办到增删改查)
4.GET和POST
4.1、GET
  • 在请求URL后面以?的形式跟上发给服务器的参数,多个参数之间用&隔开,比如:http://ww.test.com/login?username=123&pwd=234&type=JSON
  • 由于浏览器和服务器对URL长度有限制,因此在URL后面附带的参数是有限制的,通常不能超过1KB
  • 如果仅仅是索取数据(数据查询),建议使用GET
4.2、POST
  • 发给服务器的参数全部放在请求体中
  • 理论上,POST传递的数据量没有限制(具体还得看服务器的处理能力)
  • 如果要传递大量数据,比如文件上传,只能用POST请求
  • GET的安全性比POST要差些,如果包含机密\敏感信息,建议用POST
  • 如果是增加、修改、删除数据,建议使用POST
5、iOS中发送HTTP请求的方案
5.1、苹果原生(自带)
  • NSURLConnection:用法简单,最古老最经典最直接的一种方案【坑比较多】
  • NSURLSession:功能比NSURLConnection更加强大,苹果目前比较推荐使用这种技术【2013推出,iOS7开始出的技术】
  • CFNetwork:NSURL*的底层,纯C语言
5.2、第三方框架
  • ASIHttpRequest:外号“HTTP终结者”,功能极其强大,可惜早已停止更新
  • AFNetworking:简单易用,提供了基本够用的常用功能,维护和使用者多
  • MKNetworkKit:简单易用,维护和使用者少
6、HTTP通信过程
6.1、请求
  • HTTP协议规定:1个完整的由客户端发给服务器的HTTP请求中包含以下内容
  • 请求头:包含了对客户端的环境描述、客户端请求信息等
  • GET /minion.png HTTP/1.1 // 包含了请求方法、请求资源路径、HTTP协议版本
  • Host: 120.25.226.186:32812 // 客户端想访问的服务器主机地址
  • User-Agent: Mozilla/5.0 // 客户端的类型,客户端的软件环境
  • Accept: text/html, / // 客户端所能接收的数据类型
  • Accept-Language: zh-cn // 客户端的语言环境
  • Accept-Encoding: gzip // 客户端支持的数据压缩格式
  • 请求体:客户端发给服务器的具体数据,比如文件数据(POST请求才会有)
6.2、响应
  • 客户端向服务器发送请求,服务器应当做出响应,即返回数据给客户端
  • HTTP协议规定:1个完整的HTTP响应中包含以下内容:
  • 响应头:包含了对服务器的描述、对返回数据的描述:
  • HTTP/1.1 200 OK // 包含了HTTP协议版本、状态码、状态英文名称
  • Server: Apache-Coyote/1.1 // 服务器的类型
  • Content-Type: image/jpeg // 返回数据的类型
  • Content-Length: 56811 // 返回数据的长度
  • Date: Mon, 23 Jun 2014 12:54:52 GMT // 响应的时间
  • 响应体:服务器返回给客户端的具体数据,比如文件数据
6.3、常见的响应状态码
常见服务器响应的状态码

三、NSURLConnection

1、NSURLConnection的使用步骤
  • 创建一个NSURL对象,设置请求路径
  • 传入NSURL创建一个NSURLRequest对象,设置请求头和请求体(POST请求的时候使用NSMutableURLRequest设置请求体,GET和POST请求头已经默认设置好了)
  • 使用NSURLConnection发送请求
1.1、NSURLConnection使用图示
NSURLConnection使用图示
2.NSURLConnection实际使用
2.1、NSURLConnection的基本使用
//发送异步请求:不会卡住当前线程
- (void)async{
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@", string);
        //获取响应头信息
        NSHTTPURLResponse *r = (NSHTTPURLResponse *)response;
        NSLog(@"%zd %@", r.statusCode, r.allHeaderFields);
    }];
}

//发送同步请求:卡住当前线程,直到请求完成
- (void)sync{
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=123&pwd=345"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSHTTPURLResponse *response = nil;
    NSError *error = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    
    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@ %@", string, response.allHeaderFields);
}
2.2、NSURLConnection的代理方式:拿到connection对象调用cancel方法可以取消请求
- (void)delegateAysnc{
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    [NSURLConnection connectionWithRequest:request delegate:self];//自动请求
    //[[NSURLConnection alloc] initWithRequest:request delegate:self];//自动请求

    //startImmediately:YES:立即自动请求,NO:调用conn的start方法才会请求
    //NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
}

//<NSURLConnectionDataDelegate>
// 接收到服务器的响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
}
 //接收到服务器的数据(如果数据量比较大,这个方法会被调用多次)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
}
//服务器的数据成功接收完毕
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
}
//请求失败(比如请求超时)
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
}
2.3、NSMutableURLRequest简介
//设置请求超时等待时间(超过这个时间就算超时,请求失败)
- (void)setTimeoutInterval:(NSTimeInterval)seconds;

//设置请求方法(比如GET和POST)
- (void)setHTTPMethod:(NSString *)method;

//设置请求体
- (void)setHTTPBody:(NSData *)data;

//设置请求头
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field;

2.4、NSURLConnection发送POST请求
- (void)sendPOSTRequest {
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    request.HTTPBody = [@"username=520it&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding];
    request.timeoutInterval = 5;
    // 设置请求头
    //[request setValue:@"iOS 9.0" forHTTPHeaderField:@"User-Agent"];
    
    // 3.发送请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    }];
}
2.5、URL中文转码
//URL中包含中文的话需要进行转码,否则识别不了
- (nullable NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)enc;

四、JSON&XML

1、JSON
  • 第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)
  • 苹果原生(自带):NSJSONSerialization(性能最好)
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
2、XML
  • 全称是Extensible Markup Language,译作“可扩展标记语言”,跟JSON一样,也是常用的一种用于交互的数据格式,一般也叫XML文档(XML Document)
  • 一个常见的XML文档一般由以下部分组成:
    文档声明
    元素(Element)
    属性(Attribute)
2.1、文档声明
  • 在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型
  • 最简单的声明:
    <?xml version="1.0" ?>
  • 用encoding属性说明文档的字符编码:
    <?xml version="1.0" encoding="UTF-8" ?>
2.2、元素(Element)
  • 一个元素包括了开始标签和结束标签
  • 拥有内容的元素:<video>小黄人</video>
  • 没有内容的元素:<video></video>
  • 没有内容的元素简写:<video/>
  • 一个元素可以嵌套若干个子元素(不能出现交叉嵌套)


    元素嵌套
  • 规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素
2.3、属性(Attribute)
  • 一个元素可以拥有多个属性
    <video name="小黄人 第01部" length="30" />
  • video元素拥有name和length两个属性
  • 属性值必须用 双引号"" 或者 单引号'' 括住
3、XML的解析
3.1、DOM&SAX
  • DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
  • SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件
3.2、解析方式
  • 苹果原生
    NSXMLParser:SAX方式解析,使用简单
  • 第三方框架
    libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
    GDataXML:DOM方式解析,由Google开发,基于libxml2
  • XML解析方式的选择建议
    大文件:NSXMLParser、libxml2
    小文件:GDataXML、NSXMLParser、libxml2
3.3、GDataXML的配置

3.3.1、GDataXML下载地址 密码:hsfn
3.3.2、导入libxml2库:

导入libxml2库
3.3.3、设置libxml2的头文件搜索路径(为了能找到libxml2库的所有头文件):在Head Search Path中加入/usr/include/libxml2
3.3.4、设置链接参数(自动链接libxml2库:在Other Linker Flags中加入-lxml2
3.4、NSXMLParser解析示例:
//XML大致格式
<videos>
    <video id="1" name="xxx" length="xxx" url="xxx" image= "xxx"/>
    <video id="2" name="xxx" length="xxx" url="xxx" image= "xxx"/>
    <video id="3" name="xxx" length="xxx" url="xxx" image= "xxx"/>
</videos>
- (void)NSXMLParserTest {
    [super viewDidLoad];
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
        parser.delegate = self;
        [parser parse];//会阻塞当前线程
    }];
}

#pragma mark - <NSXMLParserDelegate>

//解析到某个元素的结尾(比如解析</videos>)
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
}

// 解析到某个元素的开头(比如解析<videos>)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
    if ([elementName isEqualToString:@"videos"]) return;
    VideoModel *video = [VideoModel objectWithKeyValues:attributeDict];
    [self.videos addObject:video];
}


//开始解析XML文档
- (void)parserDidStartDocument:(NSXMLParser *)parser{
}

//解析完毕
- (void)parserDidEndDocument:(NSXMLParser *)parser{
}
3.5、GDataXML解析示例:
//XML大致格式
<videos>
    <video id="1" name="xxx" length="xxx" url="xxx" image= "xxx"/>
    <video id="2" name="xxx" length="xxx" url="xxx" image= "xxx"/>
    <video id="3" name="xxx" length="xxx" url="xxx" image= "xxx"/>
</videos>
- (void)GDataXMLTest {
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        // 加载整个文档
        GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
        
        // 获得所有video元素
        NSArray *elements = [doc.rootElement elementsForName:@"video"];
        for (GDataXMLElement *ele in elements) {
            VideoModel *video = [[VideoModel alloc] init];
            video.name = [ele attributeForName:@"name"].stringValue;
            video.url = [ele attributeForName:@"url"].stringValue;
            video.image = [ele attributeForName:@"image"].stringValue;
            video.length = [ele attributeForName:@"length"].stringValue.integerValue;
            
            [self.videos addObject:video];
        }
    }];
}
上一篇下一篇

猜你喜欢

热点阅读