AFNetworking serializer 分析
1. AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; 所有的網絡請求,均有manager發起 2. 需要注意的是,默認提交請求的數據是二進制的,返回格式是JSON 如果提交數據是JSON的,需要將請求格式設置為AFJSONRequestSerializer 3. 請求格式 AFHTTPRequestSerializer 二進制格式 AFJSONRequestSerializer JSON AFPropertyListRequestSerializer PList(是一種特殊的XML,解析起來相對容易) 4. 返回格式 AFHTTPResponseSerializer 二進制格式 AFJSONResponseSerializer JSON AFXMLParserResponseSerializer XML,只能返回XMLParser,還需要自己通過代理方法解析 AFXMLDocumentResponseSerializer (Mac OS X) AFPropertyListResponseSerializer PList AFImageResponseSerializer Image AFCompoundResponseSerializer 組合
演示代碼如下:
一:提交數據是JSON格式
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init]; [dict setObject:@"apple" forKey:@"brand"]; NSString *url=@"http://xxxxx"; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.responseSerializer = [AFJSONResponseSerializer serializer];//申明返回的結果是json類型 manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];//如果報接受類型不一致請替換一致text/html或別的 manager.requestSerializer=[AFJSONRequestSerializer serializer];//申明請求的數據是json類型 [manager POST:url parameters:dict success:^(AFHTTPRequestOperation *operation, id responseObject) { } failure:^(AFHTTPRequestOperation *operation, NSError *error){ } ]; 二:提交數據是NSData類型,即默認類型 NSString *str=[NSString stringWithFormat:@"https://alpha-api.app.net/stream/0/posts/stream/global"]; NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]initWithRequest:request]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, idresponseObject) { NSString *html = operation.responseString; NSData* data=[html dataUsingEncoding:NSUTF8StringEncoding]; id dict=[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"獲取到的數據為:%@",dict); }failure:^(AFHTTPRequestOperation *operation, NSError *error) { NSLog(@"發生錯誤!%@",error); }]; NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:operation]; 將所有的網絡請求都放入一個線程隊列中。 三:上傳圖片操作: UIImage * image = [UIImage imageNamed:@"imike.png"]; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; NSData *imageData = UIImageJPEGRepresentation(image, 1); NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyyMMddHHmmss"; NSString *str = [formatter stringFromDate:[NSDate date]]; NSString *fileName = [NSString stringWithFormat:@"%@", str]; NSDictionary *parameters = @{@"filename":fileName}; //申明請求的數據是json類型 manager.requestSerializer=[AFJSONRequestSerializer serializer]; //如果報接受類型不一致請替換一致text/html或別的 manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"]; [manager POST:@"http://XXX" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { // 上傳圖片,以文件流的格式 [formData appendPartWithFileData:imageData name:@"img" fileName:fileName mimeType:@"image/png"]; } success:^(AFHTTPRequestOperation *operation, id responseObject){ NSLog(@"%@",responseObject); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { }]; 四:下載圖片: NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; NSURL *URL = [NSURL URLWithString:@"http://192.168.40.10/FileDownload/WebForm1.aspx"]; NSURLRequest *request = [NSURLRequest requestWithURL:URL]; NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) { NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil]; return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]]; } completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) { NSLog(@"File downloaded to: %@", filePath); }]; [downloadTask resume];
常見的AFNetworking content-type 報錯問題整理(AFNetworking 中請求數據和 HTTP 的 Content-type 關系)
問題一: unacceptable content-type: text/plain { status code: 200, headers { "Content-Length" = 14; "Content-Type" = "text/plain;charset=utf-8"; Date = "Thu, 22 May 2014 10:37:50 GMT"; Server = "Apache-Coyote/1.1"; "Set-Cookie" ="JSESSIONID=C0DFED60A154557F8386E62AB2A066CE; Path=/FHJRDT"; } }, NSLocalizedDescription=Request failed:unacceptable content-type: text/plain} manager.responseSerializer = [AFHTTPResponseSerializerserializer]; 決定了下面responseObject返回的類型 主要理解一下幾個參數的區別: AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; // manager.requestSerializer = [AFJSONRequestSerializer serializer]; // manager.responseSerializer = [AFJSONResponseSerializer serializer]; // [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"]; // [manager.requestSerializer setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; //注意:默認的Response為json數據 // [manager setResponseSerializer:[AFXMLParserResponseSerializer new]]; // manager.responseSerializer = [AFHTTPResponseSerializer serializer];//使用這個將得到的是NSData manager.responseSerializer = [AFJSONResponseSerializer serializer];//使用這個將得到的是JSON //注意:此行不加也可以 manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json", @"text/plain", @"text/html", nil]; 另外如果AFURLResponseSerialization,告訴AFNetworking 以怎樣的方式接受數據,如果后段接口都是標准的JSON數據格式,那么很愉快的就選擇了 AFJSONResponseSerializer ,在請求成功的Block中的responseObject 就會是一個 AFNetworking 幫你解好檔的JSON,也就是一個 NSDictionary對象。 但有時候你是否遇到明明接口是返回的JSON數據,可用 AFJSONResponseSerializer 就會報錯,錯誤信息類似: Request failed: unacceptable content-type: text/html
如果接口返回的 Content-Type 和實際情況不合時,有時候是因為后端開發人員不規范,更有遇到一套接口中大多都是JSON返回,還有個別方法返回純文本,如:“YES”,這些都是接口開發人員不規范導致的問題,作為iOS端,解決方案: responseSerializer 使用 AFHTTPResponseSerializer,這樣就不能享受 AFNetworking 自帶的JSON解析功能了,拿到 responseObject 就是一個 Data 對象,需要自己根據需要進行反序列化。 #pragma mark - Public Method - (void)postWithManager:(id)requestOperationManager success:(HttpRequestPostSuccessBlock)success failure:(HttpRequestPostFailureBlock)failure{ AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/json", @"text/plain", @"text/html", nil]; [manager POST:[NSString stringWithFormat:@"%@%@", self.baseUrl, self.urlString] parameters:_parameters success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) { if (!operation.isCancelled) { NSString *reponStr = operation.responseString; NSData* data=[reponStr dataUsingEncoding:NSUTF8StringEncoding]; id dict=[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"獲取到的數據為:%@",dict); //成功 if (success!=nil) { success(dict); } } } failure:^(AFHTTPRequestOperation * _Nullable operation, NSError * _Nonnull error) { if (!operation.isCancelled) { if (failure!=nil) { failure(operation,error); } } }]; }
AFNetworking簡單使用
iOS開發中一般情況下,簡單地向某個Web站點簡單的頁面提交請求並獲取服務器的響應,用Xcode自帶的API就能勝任。但是在數據處理(如下載等)需要自己實現。代碼量較大,難以管理,此時可以選擇使用第三方網絡庫。常用的有AFNetworking、ASIHTTPRequest、MKNetworkKit、RestKit等
下面介紹AFNetworking
AFNetworking是一個能夠快速使用的iOS和Mac OS X 下的網絡框架,它構建在Foundation URL Loading System之上,封裝了網絡的抽象層,可以方便的使用,AFNetworking是一個模塊化架構,擁有豐富的API框架。AFNetworking是目前使用人數最多的第三方框架網絡庫。
下面將使用AFNetworking中基於NSURLSession API支持封裝的接口進行介紹。
AFNetworking重要組成部分:
-
AFURLSessionManager:創建、管理基於NSURLSessionConfiguration對象的NSURLSession對象的類,也可以管理session的數據、下載/上傳任務,實現session和其相關聯的任務的delegate方法。因為NSURLSession API設計中的不足,任何和NSURLSession相關的代碼都可以用AFURLSessionManager改善;
-
AFHTTPSessionManager:是AFURLSessionManager的子類,包裝常見的HTTP web服務操作,通過AFURLSessionManager 由NSURLSession支持。例如:GET、POST、HEAD、PUT等;
-
<AFURLRequestSerializer>:符合這個協議的對象用於處理請求,它將請求參數轉換為query string 或是 entity body 的形式,並設置必要的header;
-
<AFURLResponseSerializer>:符合這個協議的對象用於驗證、序列化響應及相關數據,轉換為有用的形式,比如JSON對象、圖像、甚至基於Mantle的模型對象;
-
AFSecurityPolicy:評估服務器對安全連接針對指定的固定證書或公共密鑰的信任,將你的服務器證書添加到app bundle,以幫助防止其他人的攻擊;
-
AFNetworkReachabilityManager-這個類監控當前網絡的可達性,提供回調block和notification,在可達性變化時調用。
使用AFNetworking做GET請求:
////做get請求///////// NSString *urlString = @"https://api.weibo.com/2/statuses/public_timeline.json"; NSDictionary *parameters = @{@"access_token":@"2.00PogMQGGQ5O2E3633c3a534p58DVB"}; //1.創建管理者 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; //2.設置請求參數的拼接 manager.requestSerializer = [AFHTTPRequestSerializer serializer]; //3.設置接受的響應數據類型 manager.responseSerializer = [AFJSONResponseSerializer serializer]; //做get請求 [manager GET:urlString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"responseObject is:%@",responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"error is:%@",error); }];
使用AFNetworking做POST請求:
//1.創建管理者 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; //2.設置請求參數的拼接 manager.requestSerializer = [AFHTTPRequestSerializer serializer]; //3.設置接受的響應數據類型 manager.responseSerializer = [AFJSONResponseSerializer serializer]; //做簡單的post請求 NSString *postUrlString = @"https://api.weibo.com/2/statuses/update.json"; NSDictionary *postDic = @{@"access_token":@"2.00PogMQGGQ5O2E3633c3a534p58DVB",@"status":@"hehehe"}; ///post上傳文本//////// [manager POST:postUrlString parameters:postDic progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"上傳成功"); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"error is:%@",error); }]; //POST上傳圖片: NSString *postImgUrlString = @"https://upload.api.weibo.com/2/statuses/upload.json"; NSDictionary *dic = @{@"access_token":@"2.00PogMQGGQ5O2E3633c3a534p58DVB",@"status":@"嘿嘿嘿、、"}; [manager POST:postImgUrlString parameters:dic constructingBodyWithBlock:^(id<</span>AFMultipartFormData> _Nonnull formData) { //將圖片轉化為data數據 NSString *imgPath = [[NSBundle mainBundle] pathForResource:@"img" ofType:@"png"]; NSData *imgData = [NSData dataWithContentsOfFile:imgPath]; //將圖片數據拼接form表單中 [formData appendPartWithFileData:imgData name:@"pic" fileName:@"img.png" mimeType:@"image/png"]; } progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"上傳成功"); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"error is:%@",error); }]; }
-使用AFNetworking做download請求:
/////執行download下載.////// AFURLSessionManager *urlManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; NSURL *url = [NSURL URLWithString:@"http://vf1.mtime.cn/Video/2012/04/23/mp4/120423212602431929.mp4"]; //創建request請求 NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:10]; //創建下載任務 NSURLSessionDownloadTask *task = [urlManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) { NSLog(@"progress is:%@",downloadProgress); } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) { //返回數據存儲的文件路徑 下載完成后數據文件將自動拷貝到該文件下 NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/123.mp4"]; //將字符串轉化為文件路徑 注意一定要使用fileURLWithPath:該方法 return [NSURL fileURLWithPath:filePath]; } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) { if (error) { NSLog(@"error is:%@",error); } NSLog(@"filePath is:%@",[NSString stringWithFormat:@"%@",filePath]); }]; //執行任務 [task resume];
