AFNetworking 3.x 详解一
首先我们来分析一下** AFHTTPSessionManager 和 AFHTTPRequestSerializer **
AFHTTPSessionManager
AFHTTPSessionManager 继承自AFURLSessionManager,虽然提供了许多对外的请求方法,但是他本身没做什么事情,都是调用了父类的方法以及AFHTTPRequestSerializer请求序列化的方法,比如发送一个GET请求对应会调用到dataTaskWithHTTPMethod
方法中,首先请求序列化,失败则提示,成功则调用父类的dataTaskWithRequest
方法发起请求。
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
}
} else {
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
AFHTTPRequestSerializer
接下来我们看下AFHTTPRequestSerializer这个类是如何进行请求序列化的
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}
这个方法用于使用指定的HTTP方法和URL字符串创建一个** nsmutableurlrequest 对象。
如果HTTP方法是GET, HEAD, DELETE,则这些参数将用于构造一个URL编码的查询字符串,该字符串被追加到请求的URL中,参数将放在url中以key=value
的方式编码。否则,将根据** parameterencoding **属性的值进行编码,并设置为请求体。
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
NSString *query = nil;
if (parameters) {
if (self.queryStringSerialization) {
NSError *serializationError;
query = self.queryStringSerialization(request, parameters, &serializationError);
if (serializationError) {
if (error) {
*error = serializationError;
}
return nil;
}
} else {
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParameters(parameters);
break;
}
}
}
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
if (query && query.length > 0) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
}
} else {
// #2864: an empty string is a valid x-www-form-urlencoded payload
if (!query) {
query = @"";
}
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}
return mutableRequest;
}
该方法使用原始请求的副本编码并返回一个带有指定参数的请求。首先会遍历** HTTPRequestHeaders 为请求设置请求头,然后根据条件设置查询参数,最后根据请求方法将 parameters **拼接到URL
或者 添加到HTTP body
中。
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]);
NSMutableURLRequest *mutableRequest = [self requestWithMethod:method URLString:URLString parameters:nil error:error];
__block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:mutableRequest stringEncoding:NSUTF8StringEncoding];
if (parameters) {
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
NSData *data = nil;
if ([pair.value isKindOfClass:[NSData class]]) {
data = pair.value;
} else if ([pair.value isEqual:[NSNull null]]) {
data = [NSData data];
} else {
data = [[pair.value description] dataUsingEncoding:self.stringEncoding];
}
if (data) {
[formData appendPartWithFormData:data name:[pair.field description]];
}
}
}
if (block) {
block(formData);
}
return [formData requestByFinalizingMultipartFormData];
}
该方法使用指定的** HTTP **方法 和 ** URLString 创建一个 NSMutableURLRequest
对象,并使用指定的参数和多部分数据块构建了一个multipart/form-data
的 HTTP **体。详解:首先判断请求方法是否不是 HEAD
和 GET
,然后根据定的HTTP方法和URL字符串创建一个NSMutableURLRequest
对象,,然后创建一个AFStreamingMultipartFormData
对象,http最终上传的数据包括参数,以及要上传的文件数据都放这里。(AFStreamingMultipartFormData
对象包含AFMultipartBodyStream *bodyStream
属性,是实现了NSInputStream
的子类,[self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead]
会将数据写入缓冲区)如果参数存在,则key-value转换成NSData封装成一个AFHTTPBodyPart
对象放入HTTPBodyParts
中,并重新设置初始和最终边界,以确保Content-Length
正确,然后返回 NSMutableURLRequest
对象。
而对于** AFJSONRequestSerializer 和 AFPropertyListRequestSerializer **,无非都是继承自AFHTTPRequestSerializer
,在
<pre>- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
</pre>方法中修改Content-Type
为application/json
或是application/x-plist
。