iOS网络层的封装

对于项目的重构,很重要的就是对网络层的重构,其实也就是对AFN的二次封装。对于AFN的介绍在前一篇:研究AFNetworking框架

AFN2.0是基于NSURLConnection封装的。而AFN3.0是基于NSURLSession封装的。(NSURLSession是iOS7推出的是为了取代NSURLConnection的)。

关于AFN3.0

HTTP协议

  1. 客户端发给服务器的HTTP请求包含了:
    请求行:请求方法、请求资源路径、HTTP协议版本号
    GET /index.htm HTTP/1.1

请求头:对客户端环境的描述,客户端请求的主机的地址。
HOST: 192.168.1.105:8080
User-Agent:MAC或者IPhone (客户端环境)
Accept:text/html (客户端所能接受的数据类型)
Accept-Language:zh-cn (客户端的语言)

在POST中有请求体:客户端发给服务器的具体数据

  1. 服务器返回给客户端的HTTP响应包含了:(NSHTTPUELResponse)

状态行:协议版本、状态码、状态英文名称
HTTP/1.1 200 OK

响应头:对服务器的描述、对返回数据的描述。
Server:Apache (服务器)
Date: Sat, 22:07:00 GMT
Content-Length: 500 (返回数据长度)
Content-Type: text/html (返回数据类型)

…..

实体内容:服务器返回给客户端的具体数据

屏幕快照 2016-11-07 下午4.44.02.png

  1. GET与POST
    GET:所有的请求参数都拼接在URL后面,如果访问资源,向服务器索要数据就是GET请求。URL长度有限,不能发送太多数据

POST:把所有请求参数放在请求体(HTTPBody)中,发给服务器的长度没有限制,
200:请求成功。 400:客户端请求的语法错误,服务器无法解析。
404:服务器无法根据客户端的请求找到资源。
500:服务器内部错误,无法完成请求。

URL还要注意对中文的转码:
方法:urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

如何使用 NSURLSession 发出 HTTP 请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1.得到session对象
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"http://。。。/Server/login"];
// 创建一个请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 设置请求体
request.HTTPBody = [@"username=123&pwd=123" dataUsingEncoding:NSUTF8StringEncoding];
// 设置请求头信息
[request setValue:@"iPhone 6" forHTTPHeaderField:@"User-Agent"];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//系统的解析方法
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"----%@", dict);
}];
// 3.开始任务
[task resume];

如何使用 AFNetworking 发出 HTTP 请求

1
2
3
4
5
6
7
8
9
10
11
12
13
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:@"http://baidu.com/verification/user/loginNew.htm?token=&random=27289&version=1.19.0" parameters:dict progress:^(NSProgress * _Nonnull downloadProgress) {
NSLog(@"请求成功");
}success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//请求返回的数据(二进制数据)
NSLog(@"responseObject(二进制) = %@",responseObject);
//转化二进制数据
NSLog(@"responseObject = %@", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
[self oaLoginSuccess];
}failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"%@",error); //这里打印错误信息
}];

注意:在 iOS9 中,苹果默认全局 HTTPs,如果你要发送不安全的 HTTP 请求,需要在 info.plist 中加入如下键值对才能发出不安全的 HTTP 请求.
还有一件事情是要注意的是,AFNetworking 默认接收 json 格式的响应(因为这是在 iOS 平台上的框架,一般不需要 text/html),如果想要返回 html,需要设置 acceptableContentTypes

AFN中的相应类

AFURLSessionManager(核心类)

AFURLSessionManager 是 AFHTTPSessionManager 的父类
AFURLSessionManager 负责生成 NSURLSession 的实例,管理 AFSecurityPolicy 和 AFNetworkReachabilityManager,来保证请求的安全和查看网络连接情况,它有一个 AFJSONResponseSerializer 的实例来序列化 HTTP 响应

AFHTTPSessionManager

其中 AFHTTPSessionManager 有着自己的 AFHTTPRequestSerializer 和 AFJSONResponseSerializer 来管理请求和响应的序列化,同时依赖父类提供的接口保证安全、监控网络状态,实现发出 HTTP 请求这一核心功能

AFURLRequestSerialization

主要用于 AFHTTPSessionManager 中,因为它主要用于修改 HTTP 头部,提供了一些语义明确的接口设置 HTTP 头部字段。HTTP 头部字段 Accept-Language User-Agent

AFURLResponseSerialization

处理响应的模块,将请求返回的数据解析成对应的格式。这个模块使用在 AFURLSessionManager 也就是核心类中

为什么要对AFN进行二次封装呢?

上面这种写法可维护性差:主要是因为:

  1. 地址是写死的字符串,对于一个应用来说,网络请求的地址通常是统一而且具有规律的。如果大量的请求都用这种写法,那么想要统一进行修改的话就变得很困难。
  2. 没有统一的请求和响应过滤机制。通常客户端开发当中需要对于请求和响应进行一些处理,例如在请求中加入验证字段(如 Token),以验证请求的合法性。
  3. 对 AFNetworking 产生了强依赖,如果要进行网络库的替换,成本会非常高。

随着应用复杂程度的增加,上面这种在控制层直接对网络请求层进行交互的方式,会产生越来越多的问题。因此有必要通过单独的一层把控制层(业务层)和网络请求层隔离开来,这一层我们暂时把它叫做“网络封装层”。

封装的目标

  1. 监测网络状态
  2. 业务层和网络层分离
  3. 处理环境的变化,开发,测试,预发布,发布
  4. 处理GET、POST、下载、上传的操作
  5. 如何封装

    封装主要是把业务层和网络层分开,此次的封装分为三层:

    第一层:首先,从应用层ViewController获取参数,这个参数传到第二层的业务Service,在回调中利用网络请求返回的responseModel来显示在页面上。
    第二层:设置一个BaseService,然后+LoginService。BaseService中主要是配置公有的参数。在每个业务层的Service中设置每一个的接口定义。业务层主要是暴露接口的定义,而BaseService中定义了BaseRequestModel来实现发起请求到第三层Client。
    第三层:这层就是CLient,由ASI或者AFN充当,发起网络请求。这一层最好是个单例,

BaseRequestModel中定义了:

1
2
3
4
5
6
7
8
9
10
11
12
@interface PLHRequestModel : NSObject

//网络请求参数
@property (nonatomic, nonnull, copy) NSString * serverRoot; //网络请求的根地址
@property (nonatomic, nonnull, copy) NSString * actionPath;//发起响应的二级地址
@property (nonatomic, assign) float timeout; //时间
@property (nonatomic, assign) PLHHTTPRequestType requestType; //网络请求方式
@property (nonatomic, nonnull, copy) NSString * serviceName;
@property (nonatomic, nullable, copy) NSString *apiVersion;
@property (nonatomic, nullable, copy) NSDictionary *parameters; // 请求参数
@property (nonatomic, assign) PLHHTTPServiceType serviceType;
@end

Client

单例的,定义了AFURLSessionManager *sessionManager;生成并且发出网络请求。或者直接继承自AFURLSessionManager

PLHHTTPRequestSerializer

单例的,生成AFHTTPRequestSerializer,或者直接继承自AFHTTPRequestSerializer。为的是生成NSURLRequest

PLHRequestModel

PLHResponseModel

参考

AFNetworking 概述

文章目录
  1. 1. 关于AFN3.0
    1. 1.1. HTTP协议
      1. 1.1.1. 如何使用 NSURLSession 发出 HTTP 请求
      2. 1.1.2. 如何使用 AFNetworking 发出 HTTP 请求
      3. 1.1.3. AFN中的相应类
        1. 1.1.3.0.1. AFURLSessionManager(核心类)
        2. 1.1.3.0.2. AFHTTPSessionManager
        3. 1.1.3.0.3. AFURLRequestSerialization
        4. 1.1.3.0.4. AFURLResponseSerialization
    2. 1.1.4. 为什么要对AFN进行二次封装呢?
    3. 1.1.5. 封装的目标
  2. 1.2. 如何封装
    1. 1.2.1. Client
      1. 1.2.1.1. PLHHTTPRequestSerializer
      2. 1.2.1.2. PLHRequestModel
      3. 1.2.1.3. PLHResponseModel
  3. 1.3. 参考
,