基于ASI之后,AFN应该是比较流行的ios第三方。GIthub AFNetWorking.
这里,先贴我之前做项目 基于AFN的封装。之后,解释下AFNetWorking 的相关知识,AFURLConnectionOperation,SSL 安全AFSecurityPolicy。

项目AFNetWorking 请求封装部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
	#关于 基于AFN网络请求的get,post方法
// BaseDataService.m
// LvJinKu
//
// Created by lvjinku on 15/9/8.
// Copyright (c) 2015年 lvjinku. All rights reserved.
//

#import "BaseDataService.h"
#import "DFReachabilityUtil.h"
#import "NSString+RRAPI.h"
#import "JSONKit.h"

static const NSString *LvJinKuAgency = @"root";
static const NSString *LvJinKuSecurity = @"permission";

@interface BaseDataService()

@property (nonatomic,strong) NSMutableDictionary *requestParams;

-(NSString *) acquireBaseRequestParamDictionary;

@end

@implementation BaseDataService
@synthesize manager,requestType,requestParams;

#pragma mark - Lifecycle

- (instancetype)init
{
self = [super init];
if (self) {
manager = [[AFHTTPRequestOperationManager alloc] init];
manager.requestSerializer.timeoutInterval = NetworkTimeoutInterval;
requestType = RequestTypeGet;
requestParams = [NSMutableDictionary dictionary];
}
return self;
}


#pragma mark - Method

-(void)executeRequest
{
//网络不可用
if (![DFReachabilityUtil isNetworkAvailable]) {

NSError *error = [NSError errorWithDomain:CustomErrorDomain code:CustomErrorConnectFailed userInfo:nil];
[self onError:error];
return;
}

switch (requestType) {
case RequestTypeGet:
{

NSDictionary *requestParamsDic = @{@"xml":[self acquireBaseRequestParamDictionary]};
NSLog(@"get请求参数:%@", [self acquireBaseRequestParamDictionary]);

//参数,简单的get请求
[manager GET:[self getRequestDomain] parameters:requestParamsDic success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self onSuccess:responseObject];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"错误日志:%@",error.localizedDescription);
[self onError:error];
}];

break;
}

case RequestTypePost:
{
//参数,简单的post请求
NSDictionary *requestParamsDic = @{@"xml":[self acquireBaseRequestParamDictionary]};
[manager POST:[self getRequestDomain] parameters:requestParamsDic success:^(AFHTTPRequestOperation *operation, id responseObject){

[self onSuccess:responseObject];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self onError:error];
}];

break;
}
case RequestTypePostMultipart:
{

//检查是否为文件类型
BOOL isFile = NO;
for (NSString * key in requestParams.allKeys)
{
id value = requestParams[key];
//判断请求参数是否是文件数据
if ([value isKindOfClass:[NSData class]]) {

isFile = YES;
break;
}
}

if(isFile)
{
//上传文件
[manager POST:[self getRequestDomain] parameters:requestParams constructingBodyWithBlock:^(id formData) {
for (NSString *key in requestParams) {
id value = requestParams[key];
if ([value isKindOfClass:[NSData class]]) {
[formData appendPartWithFileData:value name:key fileName:key mimeType:@"image/jpeg"];
}
}

} success:^(AFHTTPRequestOperation *operation, id responseObject) {

[self onSuccess:responseObject];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

[self onError:error];

}];
}

break;
}
default:
break;
}

}

-(NSString *) getRequestDomain
{
return @"https://www.lvjinku.com/Home/Router/doRoute";
}

-(void) onSuccess:(id)result
{
if (result) {
BaseResponse *response = [[BaseResponse alloc] initWithData:result];
response.requestAPICode = self.requestApiCode;

if (response.error == 0) {

NSLog(@"reqest finished:%@",result);
//解析,将responseObject设置成model对象
[self parseResponse:response];

if (_delegate && [_delegate conformsToProtocol:@protocol(DataServiceDelegate)] && [_delegate respondsToSelector:@selector(onRequestSuccess:)]) {
[_delegate onRequestSuccess:response];
}
}else{
if (_delegate && [_delegate conformsToProtocol:@protocol(DataServiceDelegate)] && [_delegate respondsToSelector:@selector(onRequestStatusError:)]) {

[_delegate onRequestStatusError:response];
}
}
}

}

-(void) onError:(NSError *)error
{
if (_delegate && [_delegate conformsToProtocol:@protocol(DataServiceDelegate)] && [_delegate respondsToSelector:@selector(onRequestError:)]) {
[_delegate onRequestError:error];
}
}


//配置请求参数 xml的值
-(NSString *) acquireBaseRequestParamDictionary
{
[self setRequestParams:self.requestParams];

//json字符串
NSMutableDictionary *baseRequestDictionary = [NSMutableDictionary dictionary];
[baseRequestDictionary setObject:LvJinKuAgency forKey:@"agency"];
[baseRequestDictionary setObject:LvJinKuSecurity forKey:@"security"];
[baseRequestDictionary setObject:[self getAPIRequestMethodName] forKey:@"serviceCode"];
[baseRequestDictionary setObject:self.requestParams forKey:@"params"];


NSString *requestParamJsonStr = [self.requestParams JSONString];
NSString *tokenIdStr = [NSString stringWithFormat:@"%@%@%@%@",LvJinKuAgency,LvJinKuSecurity,[self getAPIRequestMethodName],requestParamJsonStr];
NSString *tokenId = [tokenIdStr MD5Code];
[baseRequestDictionary setObject:tokenId forKey:@"tokenid"]; //md5加密

NSString *baseRequestParamJsonStr = [baseRequestDictionary JSONString];
return baseRequestParamJsonStr;

}

/**
* 获取请求api的具体接口方法名
*
* @return <#return value description#>
*/
-(NSString *) getAPIRequestMethodName
{
return @"";
}

/**
* 解析response 字段
*
* @param response <#response description#>
*/
-(void) parseResponse:(BaseResponse *)response
{
//子类覆盖该方法进行解析
}
@end

【后面我将会结合Http请求封装解耦 写一个系列关于HTTP请求自定义封装的解析,结合AFN封装,JSON解析,下拉刷新,分页】

AFNetWorking.h 文件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#import <Foundation/Foundation.h>
#import <Availability.h>

#ifndef _AFNETWORKING_
#define _AFNETWORKING_

#import "AFURLRequestSerialization.h"
#import "AFURLResponseSerialization.h"
#import "AFSecurityPolicy.h"
#import "AFNetworkReachabilityManager.h"

#import "AFURLConnectionOperation.h"
#import "AFHTTPRequestOperation.h"
#import "AFHTTPRequestOperationManager.h"

#if ( ( defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || \
( defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 ) )
#import "AFURLSessionManager.h"
#import "AFHTTPSessionManager.h"
#endif

#endif /* _AFNETWORKING_ */

一、综述

#类库的头文件AFNetworking.h引入了下面的所有类库,并可以根据不同的系统使用不同的实现方式。

1、AFURLConnectionOperation
1
2
AFURLConnectionOperation.h 文件 
@interface AFURLConnectionOperation : NSOperation <NSURLConnectionDelegate, NSURLConnectionDataDelegate, NSSecureCoding, NSCopying>

AFN最基础的类继承自NSOperation类,将网络请求依附到一个operation上。从而让我们能够有效的控制并观察一个网络请求的创建、进行、取消、完成、暂停恢复
、异常等问题及状态。

2、AFHTTPRequestOperation
1
2
3
4
5
AFHTTPRequestOperation.h 文件 
/**
`AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request.
*/
@interface AFHTTPRequestOperation : AFURLConnectionOperation

HTTP或HTTPS协议请求的AFURLConnectionOperation的子类。它封装的可接受状态码和内容的类型,判定一个请求结果是成功或失败。实际上对系统的HTTP网络请求增加了几个HTTP需要用到的参数。

3、AFHTTPRequestOperationManager

这个类是AFN类库的核心类。它封装完成了一种通用的模式,可以帮助我们轻松友好的完成请求的创建、响应的系列化,网络状态的监控以及安全策略以及每一个请求operation的管理(operation的相互依赖或状态改变)。

4、AFURLSessionManager

iOS7之后,苹果增加了新的网络请求类–NSURLSession。
AFN官方推荐iOS 7 或者 Mac OS X 10.9以上的,最好使用该类发起网络请求,取代AFHTTPRequestOperationManager。基于目前国内app大都最低适配的iOS6,该类的用途还不是太广泛。

5、AFNetworkReachabilityManager

网络的连通状态监控以及网络的类型。实际是将苹果官方提供的Reachability的类名和通知名更换了一下,防止和系统提供的类的通知名以及类名的冲突。

6、AFURLRequestSerialization

1:符合这个协议的对象用于处理请求,它将请求参数转换为 query string 或是 entity body 的形式,并设置必要的 header。
2:构建multipart请求。

7、AFURLResponseSerialization

遵循AFURLResponseSerialization协议的对象,用于验证、序列化响应及相关数据,转换为有用的形式,比如 JSON 对象、图像、甚至基于mantle的模型对象。

8、AFSecurityPolicy

基于HTTPS 配置一些请求证书相关的安全策略。
讲到AFSecurityPolicy ,有必要先了解一下HTTPS.
HTTPS 连接建立过程大致是,客户端和服务端建立一个连接,服务端返回一个证书,客户端里存有各个受信任的证书机构根证书,用这些根证书对服务端 返回的证书进行验证,经验证如果证书是可信任的,就生成一个pre-master secret,用这个证书的公钥加密后发送给服务端,服务端用私钥解密后得到pre-master secret,再根据某种算法生成master secret,客户端也同样根据这种算法从pre-master secret生成master secret,随后双方的通信都用这个master secret对传输数据进行加密解密。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 

AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
[securityPolicy setAllowInvalidCertificates:NO];
[securityPolicy setSSLPinningMode:AFSSLPinningModeCertificate];
[securityPolicy setValidatesDomainName:YES];
[securityPolicy setValidatesCertificateChain:NO];

manager.securityPolicy = securityPolicy;

## SSL Pinning Modes

The following constants are provided by `AFSSLPinningMode` as possible SSL pinning modes.

enum {
AFSSLPinningModeNone,
AFSSLPinningModePublicKey,
AFSSLPinningModeCertificate,
}

AFSSLPinningModeNone: 代表客户端无条件地信任服务器端返回的证书。
AFSSLPinningModePublicKey: 代表客户端会将服务器端返回的证书与本地保存的证书中,PublicKey的部分进行校验;如果正确,才继续进行。
AFSSLPinningModeCertificate: 代表客户端会将服务器端返回的证书和本地保存的证书中的所有内容,包括PublicKey和证书部分,全部进行校验;如果正确,才继续进行。
AFSecurityPolicy相关更多知识可以了解这篇文章 AFSecurityPolicy

AFURLConnectionOperation 实现分析

1、综述
AFURLConnectionOperation将Operation和URLConnection结合到一起,利用operation可以监听到状态以及可以建立相互之间的依赖关系的特性,实现了对于一个NSURLConnection对象的完美控制,并将请求的结果通过block友好的返回。

2、实现文件.m
我们总结下.m中这个类主要有哪些方法。

1):首先我们可以看到它创建了一个单例线程。这个线程将会常驻内存,用来处理AFN发起的所有请求任务。当然,线程也跟随着一个runloop,AFN将这个runloop的模式设置为NSDefaultRunLoopMode。NSDefaultRunLoopMode是无法检测到connection的状态的。这说明了,AFN将不会在这该线程处理connection完成后的UI刷新等工作,而是会将数据抛给主线程,让主线程去完成UI的刷新。
2):我们可以看到该类通过接受请求的字符串,创建了URLRequest以及NSURLConnection对象。从而去进行请求。
3):实现文件多次使用到了锁,可以保证数据的安全。当然他也实现了几个数据的NSCoping协议。
4):请求的创建、进行、取消、完成、暂停恢复、异常等问题及状态的控制。这里讲一下暂停和恢复。暂停实际上将网络请求取消掉了。但是由于实现了nscoping协议,已经下载到数据得以保存下来。下次进行相同请求的时候,我们会将已经下载到的数据的节点一起发送给服务器,告诉服务器这些部门的数据我们不需要了,服务器根据我发送的返回节点给我返回相应的数据即可。从而实现了暂停和恢复功能,也就是断点续传。
5):operation方法的重写。
6):状态的各种控制方法的实现以及发送状态改变的通知

3、接口文件.h
接口文档中的属性方法,基本可以概括为以下几个方法

1):只读的数据,让管理者可以接收到。
2):设置runloop的modes。不再使用类库默认设置的defaultmodes。
3):状态的控制方法
4):安全策略的设置总而言之,接口文件.h暴露的接口都是为了让manager可以去完全控制这个operation以及其中的网络请求。

AFHTTPRequestOperationManger

2.0后,AFN将一些设置提取出来,线程了专门的类【AFSecurityPolicy、AFURLRequestSerialization、AFURLResponseSerialization】。现在看来,AFN整体的设计是非常完美的。耦合性变得非常低,一些1.0版本中存在的问题也得到了改善。

1、实现文件.m
实现文件较为简单,可以看到他创建了一个队列。并将各个operation加入到队列中。在队列中,各个请求就可以设置依赖关系,并发的数量等等。

2、接口文件.h
接口文件中,我们可以看到。这个类可以设置AFSecurityPolicy、AFURLRequestSerialization、AFURLResponseSerialization 等参数了。这就是综述所说的降低耦合性的方式。

评论