Serialization 包括
AFURLResponseSerialization
和AFURLRequestSerialization
AFURLResponseSerialization 是处理响应的模块,将请求返回的数据解析成对应的格式。而AFURLRequestSerialization的主要作用是修改请求(主要是 HTTP 请求)的头部,提供了一些语义明确的接口设置 HTTP 头部字段。
AFURLResponseSerialization
AFURLResponseSerialization 是一个协议,协议的内容为:
1 | - (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response |
它的实现类为:
- AFURLResponseSerialization
- AFHTTPResponseSerializer
- AFJSONResponseSerializer
- AFXMLParserResponseSerializer
- AFXMLDocumentResponseSerializer
- AFPropertyListResponseSerializer
- AFImageResponseSerializer
- AFCompoundResponseSerializer
- AFHTTPResponseSerializer
在文件中 所有类都遵循AFURLResponseSerialization,而AFHTTPResponseSerializer是其他类的基类。
AFHTTPResponseSerializer
初始化:
1 | + (instancetype)serializer { |
因为是对 HTTP 响应进行序列化,所以这里设置了 stringEncoding 为 NSUTF8StringEncoding 而且没有对接收的内容类型加以限制。
将 acceptableStatusCodes 设置为从 200 到 299 之间的状态码, 因为只有这些状态码表示获得了有效的响应。
验证响应的有效性:
1 | - (BOOL)validateResponse:(NSHTTPURLResponse *)response |
这个方法根据在初始化方法中初始化的属性 acceptableContentTypes 和 acceptableStatusCodes 来判断当前响应是否有效。
AFURLResponseSerialization协议的实现
1 | - (id)responseObjectForResponse:(NSURLResponse *)response |
调用上面的方法对响应进行验证,然后返回数据
AFJSONResponseSerializer
初始化:
1 | + (instancetype)serializer { |
相对AFHTTPResponseSerializer 设置了acceptableContentTypes;
AFURLResponseSerialization协议的实现:
1 | - (id)responseObjectForResponse:(NSURLResponse *)response |
1. 验证请求
1 | if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { |
调用自身的validateResponse验证响应,
validateResponse:中如果content-type不满足,那么产生的validationError就是Domain为AFURLResponseSerializationErrorDomain,code为NSURLErrorCannotDecodeContentData,再用 AFErrorOrUnderlyingErrorHasCodeInDomain检验error 和domain,如果就是这两个值 就返回nil。
2. 解决一个由只包含一个空格的响应引起的 bug
1 | BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]]; |
对于’head :ok’,Rails返回的是一个空格 (这是Safari上的一个bug),并且这样的JSON格式不会被NSJSONSerialization解析。如果是单个空格,就不解析
查看 Issues 1742
3.序列化 JSON
1 | NSError *serializationError = nil; |
使用系统自带的NSJSONSerialization来解析NSData数据,如果serializationError不为空,那么最终的error其实就是serializationError
4. 移除 JSON 中的 null
1 | if (self.removesKeysWithNullValues) { |
AFJSONObjectByRemovingKeysWithNullValues通过递归的方法,把JSON中NSDictionary的数据(不包括NSArray)中的对应value为空的key移除。
AFURLRequestSerialization
AFURLRequestSerialization 的主要工作是对发出的 HTTP 请求进行处理。
使用
1 | [[AFHTTPRequestSerializer serializer] requestWithMethod:@"GET" URLString:URLString parameters:parameters error:nil]; |
AFURLRequestSerialization
AFURLRequestSerialization 是一个协议
1 | - (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request |
它的实现类为:
- AFURLRequestSerialization
- AFHTTPRequestSerializer
- AFJSONRequestSerializer
- AFPropertyListRequestSerializer
- AFHTTPRequestSerializer
AFHTTPRequestSerializer是所有类的基类,AFJSONRequestSerializer 和 AFPropertyListRequestSerializer继承了AFHTTPRequestSerializer。
AFHTTPRequestSerializer
初始化:
1 | + (instancetype)serializer { |
1. 初始化参数
1 |
|
初始化了一些参数 ,HTTPMethodsEncodingParametersInURI表示需要将的quey是拼接到url后面的的方法,就是GET HEAD DELETE
,与此对应的POST PUT
方法将query拼到http body中。mutableHTTPRequestHeaders 储存http头部信息。mutableObservedChangedKeyPaths保存需要键值观察的值。
requestHeaderModificationQueue ??
2. 设置HTTP 头部字段
1 | NSMutableArray *acceptLanguagesComponents = [NSMutableArray array]; |
分别设置了acceptLanguagesComponents和userAgent信息。
其中acceptLanguagesComponents
一般为:1
en;q=1
userAgent为:1
[工程名字]/[工程版本] (iPhone; iOS 10.2; Scale/2.00)
3.KVO
1 | for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) { |
对一些属性进行 KVO,确保它们在改变后更新 NSMutableURLRequest 中对应的属性。其中AFHTTPRequestSerializerObservedKeyPaths为这些值: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//是否允许使用设备的蜂窝移动网络来创建request,默认为允许
allowsCellularAccess,
/* 创建的request所使用的缓存策略,默认使用`NSURLRequestUseProtocolCachePolicy`,该策略表示
如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断
下一步操作,如: Cache-Control字段为must-revalidata, 则 询问服务端该数据是否有更新,无更新话
直接返回给用户缓存数据,若已更新,则请求服务端.*/
cachePolicy,
/**
如果设置HTTPShouldHandleCookies为YES,就处理存储在NSHTTPCookieStore中的cookies
HTTPShouldHandleCookies表示是否应该给request设置cookie并随request一起发送出去
*/
HTTPShouldHandleCookies,
/**
HTTPShouldUsePipelining表示receiver(理解为iOS客户端)的下一个信息是否必须等到上一个请求回复才能发送。
如果为YES表示可以,NO表示必须等receiver收到先前的回复才能发送下个信息。
*/
HTTPShouldUsePipelining,
/**
设定request的network service类型. 默认是`NSURLNetworkServiceTypeDefault`.
这个network service是为了告诉系统网络层这个request使用的目的
比如NSURLNetworkServiceTypeVoIP表示的就这个request是用来请求网际协议通话技术(Voice over IP)。
系统能根据提供的信息来优化网络处理,从而优化电池寿命,网络性能等等
*/
networkServiceType,
/**
超时机制,默认60秒
*/
timeoutInterval
AFURLRequestSerialization 协议的实现
初始化之后,如果调用了 - [AFHTTPSessionManager dataTaskWithHTTPMethod:URLString:parameters:uploadProgress:downloadProgress:success:failure:],就会进入 AFHTTPRequestSerializer 的这一方法:
1 | - (NSMutableURLRequest *)requestWithMethod:(NSString *)method |
其中调用了AFURLRequestSerialization 协议的实现:
1 | - (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request |
1.通过 HTTPRequestHeaders 字典设置头部字段
1 | [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { |
2. 将parameters转换为查询参数query
1 | query = AFQueryStringFromParameters(parameters); |
AFQueryStringFromParameters (调用)-> AFQueryStringPairsFromDictionary -> AFQueryStringPairsFromKeyAndValue
其中AFQueryStringPairsFromKeyAndValue递归调用并解析,返回查询参数。
3. 将 query 添加到 URL 或者 HTTP body 中
1 | if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { |
最后这个方法会返回一个 NSMutableURLRequest。