科普 ContentType
Content-Type,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件与内容,这就是经常看到一些网页点击的结果却是下载到的一个文件或一张图片的原因。
requestSerializer与responseSerializer
requestSerializer
简单的来说AFNetworking的requestSerializer是决定AFNetworking以何种方式格式化序列化数据(即parameters,我们通常传一个字典)去请求api。
最终后台接收到的并不是我们认为的iOS中的一个字典parameters,或一个数组parameters
AFNetworking框架自动的将其格式化序列化成JSON、XML、等等文本格式,编码后放到HTTP请求的Body中,最后由后台API接收到。
请求的数据编码格式
而AFNetworking请求的数据编码格式又以下几种:
AFHTTPRequestSerializer 二进制
AFJSONRequestSerializer JSON
AFPropertyListRequestSerializer Plist
responseSerializer
简单的来说AFNetworking的responseSerializer是决定以何种方式格式化后台API响应返回的数据。
理论上完整的HTTP响应结束后,AFNetworking收到的并不是一个字典responseObject,或一个数组responseObject对象。而是字符串或者二进制数据。
AFNetworking框架自动的将HTTP响应回来的字符串数据(JSON、XML、二进制),反序列化解析成了APP端的对象,最终反回了responseObject对象。
响应的数据解码格式
AFHTTPResponseSerializer 二进制
AFJSONResponseSerializer JSON
AFPropertyListResponseSerializer Plist
AFXMLParserResponseSerializer XML
AFImageResponseSerializer Image
AFCompoundResponseSerializer 组合的
unacceptable content-type
com.alamofire.serialization.response.error.data=<5b7b2273 74617475 73223a22 73756363 65737322 2c226d73 67223a22 e799bbe9 9986e688 90e58a9f 227d5d>, NSLocalizedDescription=Request failed: unacceptable content-type: text/html}
AFNetworking请求API遇到这个问题的原因是,HTTP响应头中的 Content-Type 与返回数据的格式不一致导致的
比如常常后台API认为返回的是JSON编码的数据,虽然看似是JSON格式没错,但其实Content-Type并不是对应的JSON类型,这会导致客户端,即AFNetworking认为返回的数据是无效的数据,从而报错。
一个方法就是后台webservice更改返回数据的Content-Type为正确的application/json和text/json
如果后端某些原因无法更改,iOS客户端可以强制把未识别的 text/html类型加到AFNetworking可识别的列表中:
Objective-C
//_sharedClient为AFHTTPRequestOperationManager或者AFHTTPSessionManager的实例对象
_sharedClient.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", @"text/plain",nil];
1
2
//_sharedClient为AFHTTPRequestOperationManager或者AFHTTPSessionManager的实例对象
_sharedClient.responseSerializer.acceptableContentTypes=[NSSetsetWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html",@"text/plain",nil];
acceptableContentTypes 为NSSet,如果缺后台对应的Content-type,可以直接添加进去
或者用更稳妥的方法,原有基础上追加Content-type
Objective-C
_sharedClient.responseSerializer.acceptableContentTypes = [_sharedClient.responseSerializer.acceptableContentTypes setByAddingObjectsFromSet:[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", @"text/plain",@"application/atom+xml",@"application/xml",@"text/xml",@"image/png",@"image/jpeg",nil]];
1
_sharedClient.responseSerializer.acceptableContentTypes=[_sharedClient.responseSerializer.acceptableContentTypessetByAddingObjectsFromSet:[NSSetsetWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html",@"text/plain",@"application/atom+xml",@"application/xml",@"text/xml",@"image/png",@"image/jpeg",nil]];
一个完整AFNetworking示例
Objective-C
+ (NSURLSessionDataTask *)X_POST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(id responseObject))success
failure:(void (^)(NSError *error))failure{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//发送json数据 {"key":"value","key2":"value2"}
manager.requestSerializer = [AFJSONRequestSerializer serializer];
//响应json数据
manager.responseSerializer = [AFJSONResponseSerializer serializer];
发送二进制form数据 key=value&key2=value2
//manager.requestSerializer = [AFHTTPRequestSerializer serializer];
响应二进制form数据
//manager.responseSerializer = [AFHTTPResponseSerializer serializer];
//直接发送JSON给服务器端 对应[AFJSONRequestSerializer serializer];
//实际httpbody中的数据为 {"name":"sky","password":"fox"}
NSDictionary *parametersDemo = @{@"name":@"sky",@"password":@"fox"};
将请求参数转换为JSON后放入key为aJSON的字典中发送请求 对应[AFHTTPRequestSerializer serializer];
实际httpbody中的数据为 {"aJSON":"{"name":"sky","password":"fox"}","key":"value"}
// NSDictionary *parametersJSON = @{@"name":@"sky",@"password":@"fox"};
//NSData *JSONData = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:nil];
//NSString *JSONString = [[NSString alloc] initWithData:parametersJSON encoding:NSUTF8StringEncoding];
//NSMutableDictionary *parametersDemo = @{@"aJSON":JSONString?:@"",@"key":@"value"};
manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObjectsFromSet:[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", @"text/plain",@"application/atom+xml",@"application/xml",@"text/xml",nil]];
return [manager POST:URLString parameters:parametersDemo progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
success(responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSString *responseString = [[NSString alloc] initWithData:(NSData *)error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] encoding:NSUTF8StringEncoding];
NSLog(@"%@",responseString);
failure(error);
}];
}
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
30
31
32
33
34
35
36
37
38
+(NSURLSessionDataTask*)X_POST:(NSString*)URLString
parameters:(id)parameters
success:(void(^)(idresponseObject))success
failure:(void(^)(NSError*error))failure{
AFHTTPSessionManager*manager=[AFHTTPSessionManagermanager];
//发送json数据 {"key":"value","key2":"value2"}
manager.requestSerializer=[AFJSONRequestSerializerserializer];
//响应json数据
manager.responseSerializer=[AFJSONResponseSerializerserializer];
发送二进制form数据 key=value&key2=value2
//manager.requestSerializer = [AFHTTPRequestSerializer serializer];
响应二进制form数据
//manager.responseSerializer = [AFHTTPResponseSerializer serializer];
//直接发送JSON给服务器端 对应[AFJSONRequestSerializer serializer];
//实际httpbody中的数据为 {"name":"sky","password":"fox"}
NSDictionary*parametersDemo=@{@"name":@"sky",@"password":@"fox"};
将请求参数转换为JSON后放入key为aJSON的字典中发送请求 对应[AFHTTPRequestSerializer serializer];
实际httpbody中的数据为 {"aJSON":"{"name":"sky","password":"fox"}","key":"value"}
// NSDictionary *parametersJSON = @{@"name":@"sky",@"password":@"fox"};
//NSData *JSONData = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:nil];
//NSString *JSONString = [[NSString alloc] initWithData:parametersJSON encoding:NSUTF8StringEncoding];
//NSMutableDictionary *parametersDemo = @{@"aJSON":JSONString?:@"",@"key":@"value"};
manager.responseSerializer.acceptableContentTypes=[manager.responseSerializer.acceptableContentTypessetByAddingObjectsFromSet:[NSSetsetWithObjects:@"application/json",@"text/json",@"text/javascript",@"text/html",@"text/plain",@"application/atom+xml",@"application/xml",@"text/xml",nil]];
return[managerPOST:URLStringparameters:parametersDemoprogress:^(NSProgress*_NonnulluploadProgress){
}success:^(NSURLSessionDataTask*_Nonnulltask,id_NullableresponseObject){
success(responseObject);
}failure:^(NSURLSessionDataTask*_Nullabletask,NSError*_Nonnullerror){
NSString*responseString=[[NSStringalloc]initWithData:(NSData*)error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]encoding:NSUTF8StringEncoding];
NSLog(@"%@",responseString);
failure(error);
}];
}
所有的ContentTypes都包含在http://www.iana.org/assignments/media-types/media-types.xhtml中