您的位置:首页 > 理论基础 > 计算机网络

AFNetworking3.1.0源码分析(六)详解AFHTTPRequestSerializer 之序列化NSMutableURLRequest

2016-12-12 13:41 639 查看
本文主要分析AFNetworking序列化NSMutableURLRequest

1:AFNetworking支持三种
media-type对应的http请求头字段Content-Type为:


①application/x-www-form-urlencoded 

②application/json

③application/x-plist 

在http请求中,请求方式为(GET,HEAD,DELEATE)都使用第①中第一种,因为这三种方式的请求参数是放在URI中,其它的(POST,PUT等)放在请求体中,对于AFNetworking默认也是支持第一种方式。

AFNetworking支持的三种方式支持的序列化请求对象和解析请求参数类有一下三个:

AFHTTPRequestSerializer

AFJSONRequestSerializer :AFHTTPRequestSerializer

AFPropertyListRequestSerializer :AFHTTPRequestSerializer

下面先说下对于application/x-www-form-urlencoded 通用标准的解析请求参数的方式

解析原理:递归解析参数,直到出现参数中最终的结构为key :value(没有嵌套类型)时生成AFQueryStringPair对象,最终生成了所有key:value方式的AFQueryStringPair对象的数组

,然后对数组中的每个对象进行百分号编码,最终使用&拼接,生成最终的query字符串。示例:

①:{"key":[{"key":"value1"},{"key":"value2"},"key1"],"key2":"value3"} --->②:key[][key]=value1&key[][key]=value2&key[]=key1&key2=value3 --->③:key%5B%5D%5Bkey%5D=value1&key%5B%5D%5Bkey%5D=value2&key%5B%5D=key1&key2=value3

//①-->②
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary);
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value);
//②-->③
NSString * AFQueryStringFromParameters(NSDictionary *parameters)
以上三个类都遵循序列化协议:

@protocol AFURLRequestSerialization <NSObject, NSSecureCoding, NSCopying>

/**
 对原始请求对象进行copy(即序列化原始request,因为从NSURLRequest定义
 @interface NSURLRequest : NSObject <NSSecureCoding, NSCopying, NSMutableCopying>
 可以知道内部已经实现了序列化协议,可以直接使用mutableCopy来序列化)

 @param request 原始请求对象
 @param parameters 需要编码的请求参数
 @param error 编码请求参数过程中出现的错误信息

 @return 返回值为经过序列化之后的请求对象
 */
- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                               withParameters:(nullable id)parameters
                                        error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;

@end

AFHTTPRequestSerializer实现序列化请求对象的方式:

①:序列化原始请求对象:

//验证原始request是否为空,如果为空就输出错误日志信息,并结束程序
NSParameterAssert(request);
//深拷贝原始request对象,并设置新request对象的请求头参数
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];

②:解析并生成query string,此处可以实现自定义的解析方式,AFNetworking抛出的有接口 queryStringSerialization block对象,默认是按照上面的application/x-www-form-urlencoded
方式:
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 {

//默认的解析方式有AFNetworking自己实现对参数的解析并生成query字符串

switch (self.queryStringSerializationStyle) {

case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParameters(parameters);
break;
}
}
}

③:设置Content-Type 和处理URI,如果是老三样(GET,HEAD,DELETE)按照RFC的规范这几种请求方式的请求参数是放在url query部分,显式的呈现在URI中,并且是默认使用application/x-www-form-urlencoded,如果是其它的(POST,PUT)则设置Content-Type为application/x-www-form-urlencoded同时设置请求体参数。因此需要做如下的判断:
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 = @"";
}
//其它方式的请求如(POST PUT )设置httpBody,默认设置Content-Type为form表单提交形式

if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {

[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
}

AFJSONRequestSerializer实现序列化请求对象的方式:

①:序列化原始请求对象:

如果是(GET,HEAD,DELETE)方式直接调用父类的序列化解析:

NSParameterAssert(request); if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { return [super requestBySerializingRequest:request withParameters:parameters error:error]; }

如果是(POST,PUT)方式先序列化原始请求对象并设置请求参数:
NSMutableURLRequest *mutableRequest = [request mutableCopy]; [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { if (![request valueForHTTPHeaderField:field]) { [mutableRequest setValue:value forHTTPHeaderField:field]; } }];

 

②:设置Content-Type为application/json
if (parameters) {
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
}
③:解析请求参数为jsondata并设置请求体参数:

if (![NSJSONSerialization isValidJSONObject:parameters]) {
if (error) {
NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"The `parameters` argument is not valid JSON.", @"AFNetworkin
4000
g", nil)};
*error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
}
return nil;
}

NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error];

if (!jsonData) {
return nil;
}

[mutableRequest setHTTPBody:jsonData];
}


AFPropertyListRequestSerializer实现序列化请求对象的方式:

①:序列化原始请求对象:

如果是(GET,HEAD,DELETE)方式直接调用父类的序列化解析:

NSParameterAssert(request);
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
return [super requestBySerializingRequest:request withParameters:parameters error:error];
}


如果是(POST,PUT)方式先序列化原始请求对象并设置请求参数:

NSMutableURLRequest *mutableRequest = [request mutableCopy];

[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];


②:设置Content-Type为application/x-plist

if (parameters) {
        if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
            [mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"];
        }


③:解析请求参数为jsondata并设置请求体参数:

 NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error];
        
        if (!plistData) {
            return nil;
        }
        
        [mutableRequest setHTTPBody:plistData];
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: