野火🔥

AFN源码分析-AFURLRequestSerialization

2016/03/12

AFURLRequestSerialization

该Class为用于对请求参数进行拼接、http body组合以及header配置。

包含3个具体的实现类:AFHTTPRequestSerializer、AFJSONRequestSerializer、AFPropertyListRequestSerializer,主要针对3种不同的请求参数组合格式。定义了一个protocol–AFMultipartFormData,用于对数据上传使用。本类中一半篇幅进行POST multi上传情况的处理。

所有HTTPHeaderField的参数都通过一个固定的setValue:forValue的方法进行设定,不再赘述。其它还可以设置需要auth的用户名密码、写在body中数据的编码格式等。有一个比较不错的设计:可以通过传入block的形式将参数部分拼接的具体实现抛回给调用方,用以特殊定制。

比较有意思的在于,本类为几个成员变量默认增加了KVO观察者。观察参数包括:allowsCellularAccess、cachePolicy、HTTPShouldHandleCookies、HTTPShouldUsePipelining、HTTPShouldUsePipelining、networkServiceType、timeoutInterval,这几个参数同时也是NSMutableURLRequest的成员变量的对应key值,通过这种方式实现了动态的参数设定:即设置当前Serializer会自动设置其Request参数。

1、请求参数设定

针对的都是GET、DELETE、HEAD请求,会将传入的NSArray、NSDictionary、NSSet parameters做格式化为URL参数,将PUT、POST、PATCH encode在body中。在对NSArray、NSDictionary、NSSet格式的参数进行处理时,首先会使用向外暴漏block进行拼接,block生成的string在url参数中会直接加载url后,body根据传入的encodeCode进行字符串编码。

2、POST文件上传

仅POST请求可以进行文件上传,content-type为multipart/form-data。本类中一般的篇幅都是对文件上传进行处理的。

在对外使用接口上,针对文件上传会通过block抛回一个id对象,调用方在此block进行文件的绑定,包括文件data、fileName以及mime等,这种设计方案在好奇心日报的Android也进行了一次基本类似的实现,经实际使用,直观好用。

具体实现是定义了一个名为AFStreamingMultipartFormData 实现了 AFMultipartFormData protocol,负责回传给调用方加以使用。

针对其中通过NSDictionary这种方式传进来得参数,类中定义个一个名为AFQueryStringPair的对象,主要对参数进行相应的格式化,转成需要key-value形式,然后通过appendPartWithFormData:name:这个方法进行拼装。针对这层数据,再使用一个名叫AFHTTPBodyPart的对象进行第二次封装,这里会封装stringEncoding,本组数据的headers,数据与数据之间的boundary,其中的body(可能是data、inputStream、fileUrl等)和对应数据长度bodyContentLength。这里非常适合在学习HTTP 1.1协议适合进行学习或者查看

此处有两个习惯比较好:一是使用NSParametersAssert对参数进行非空检查,而是对bool值得返回函数进行了error的反馈,具体看代码片段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType
error:(NSError * __autoreleasing *)error
{
NSParameterAssert(fileURL);
NSParameterAssert(name);
NSParameterAssert(fileName);
NSParameterAssert(mimeType);
if (![fileURL isFileURL]) {
NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"Expected URL to be a file URL", @"AFNetworking", nil)};
if (error) {
*error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorBadURL userInfo:userInfo];
}
return NO;
}
....
}

上面的最后会拼在一个NSInputSteam的子类AFMultipartBodyStream中,该类最后会进行流的最终拼接和上传。

上传中可以设置上传的大小以及每个具体子资源写入的延迟,用于在3G和EDGE下选择使用。(文档这么讲,不懂,以后了解)

CATALOG
  1. 1. AFURLRequestSerialization
    1. 1.1. 1、请求参数设定
    2. 1.2. 2、POST文件上传