AFNetworking3.1.0源码分析(六)详解AFHTTPRequestSerializer 之序列化NSMutableURLRequest
2016-12-12 13:41
639 查看
本文主要分析AFNetworking序列化NSMutableURLRequest
1:AFNetworking支持三种
①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)方式直接调用父类的序列化解析:
如果是(POST,PUT)方式先序列化原始请求对象并设置请求参数:
②:设置Content-Type为application/x-plist
③:解析请求参数为jsondata并设置请求体参数:
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];
相关文章推荐
- AFNetworking3.1.0源码分析(五)详解AFHTTPRequestSerializer 之创建NSMutableURLRequest
- AFNetworking3.1.0源码分析(四)详解AFHTTPRequestSerializer 之初始化方法
- AFNetworking3.1.0源码分析(七)详解AFHTTPRequestSerializer 之AFStreamingMultipartFormData上
- iOS-95-网络请求方式汇总(包含AFNetworking、NSMutableURLRequest)
- NSMutableURLRequest,在POST方式下传递参数
- NSMutableURLRequest,在POST方式下传递参数
- NSMutableURLRequest实现Post访问
- NSMutableURLRequest timeout interval 不起作用的原因
- Objective-C-使用NSMutableURLRequest发送POST请求,使用NSJSONSerialization解析JSON字符串
- iOS-NSURLConnection、NSMutableURLRequest、NSURLRequest用法
- NSMutableURLRequest Http 请求 同步 异步
- NSMutableURLRequest,在POST方式下传递参数
- 网络数据请求NSMutableURLRequest-NSHTTPURLResponse
- NSMutableURLRequest,在POST方式下传递参数
- Objective-C-使用NSMutableURLRequest发送POST请求,使用NSJSONSerialization解析JSON字符串
- 使用NSMutableURLRequest发送json数据
- NSMutableURLRequest 访问web html
- NSMutableURLRequest 发送同步请求get方法
- object-c NSMutableURLRequest模拟表单提交
- IOS成长之路-NSMutableURLRequest实现Post请求