AFNetWorking中适配iOS7的坑坑

强子的第一篇~

第一篇

好激动

正题

最近在IM开发中遇到了个奇葩的bug,使用AFNetWorking上传语音在iOS 7 上传音频文件直接失败,返回3840服务端直接拒绝~~~最后跟后台童鞋定位了,缺少了Content-Length字段,好奇特,iOS10 上没问题啊~好蛋疼...开始断点一步步滴跟~使用了下面的方法进行上传:

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

manager.responseSerializer.acceptableContentTypes= [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"image/jpeg",nil];NSMutableDictionary*para = [NSMutableDictionarydictionary];

para[@"action"] = @"999";

[manager POST:@"http://push.hjourney.cn/api.php?c=Index2"parameters:para constructingBodyWithBlock:^(id  _Nonnull formData) {

[formData appendPartWithFileData:audioData name:@"file"fileName:@"m4a"mimeType:@"audio/mpeg"];

} progress:^(NSProgress * _Nonnull uploadProgress) {floatprogress =1.0* uploadProgress.completedUnitCount/ uploadProgress.totalUnitCount;NSLog(@"上传进度-----  %f",progress);

} success:^(NSURLSessionDataTask * _Nonnull task,id_Nullable responseObject) {NSLog(@"上传成功 %@",responseObject);

} failure:^(NSURLSessionDataTask * _Nullable task,NSError* _Nonnull error) {NSLog(@"上传失败 %@",error);

}];

生成NSMutableURLRequest 头部还有Content-Length


AFNetWorking中适配iOS7的坑坑_第1张图片

然后再往下走~生成NSURLSessionUploadTask Content-Length字段没了。。。


AFNetWorking中适配iOS7的坑坑_第2张图片


然后就收到了这个错误:

_block_invoke fail:Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x16fbb260 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.

不要怀疑人生了...iOS7上Content-Length就是被"吃"了,各种谷歌~~~有结论了~NSURLSessionTask中有一个bug(苹果坑爹了。。。),当HTTP body的内容是来自NSStream的时候,request无法发送Content-Length到服务器端,此问题在Amazon S3的Web服务中尤为显著。

解决方案;

https://github.com/afnetworking/afnetworking/issues/1398

上代码~自己亲测可用!

第一种采用afnetworking 的api:

+ (void)sendAudioData

{

NSMutableDictionary*dic = [NSMutableDictionary dictionary];

[dic setObject:@"附加数据" forKey:@"mydata"];

NSString*filePath = @"音频文件路径";

NSString*url = @"上传文件的url路径";

NSString* tmpFilename = [NSString stringWithFormat:@"%f", [NSDate timeIntervalSinceReferenceDate]];

NSURL* tmpFileUrl = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:tmpFilename]];

// Create a multipart form request.

NSMutableURLRequest*multipartRequest = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST"

URLString:transcodeUrl

parameters:dic constructingBodyWithBlock:^(id formData)

{

[formData appendPartWithFileURL:[NSURL fileURLWithPath:filePath]

name:@"file"

fileName:@"m4a"

mimeType:@"audio/mpeg"error:nil];

} error:nil];

//Create default session manager.

AFURLSessionManager *manager = [[AFURLSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfigurationdefaultSessionConfiguration]];

[[AFHTTPRequestSerializer serializer] requestWithMultipartFormRequest:multipartRequest

writingStreamContentsToFile:tmpFileUrl

completionHandler:^(NSError *error) {

//将数据写入临时文件,不在使用NSStream 生成NSURLSessionUploadTask,解决Content-Length丢失问题

NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:multipartRequestfromFile:tmpFileUrl progress:^(NSProgress *_NonnulluploadProgress) {

}

completionHandler:^(NSURLResponse *response,idresponseObject, NSError *error)

{

// Cleanup: remove temporary file.

[[NSFileManager defaultManager] removeItemAtURL:tmpFileUrl error:nil];

// Do something with the result.

if(error) {

[manager.session finishTasksAndInvalidate];

}else{

if(!responseObject ||0!= ((NSString *)responseObject[@"error_code"]).integerValue)

{return;}

NSLog(@"Success:%@", responseObject);                                                                                                   

}

}];

// Start the file upload.

[uploadTask resume];

}];

}

第二种方式不使用AFNetWorking,使用NSURLSessionUploadTask上传:

代码如下

//转码

+ (void)sendAudioData

{

NSMutableDictionary*dic = [NSMutableDictionary dictionary];

[dic setObject:@"附加数据" forKey:@"mydata"];

NSString*filePath = @"音频文件路径";

NSString*url = @"上传文件的url路径";

// Create a multipart form request.

NSMutableURLRequest*request = [NSMutableURLRequestrequestWithURL:[NSURLURLWithString:url]];

request.HTTPMethod=@"POST";

NSString*boundary = [NSStringstringWithFormat:@"Boundary+%08X%08X",arc4random(),arc4random()];

//设置ContentType

NSString*contentType = [NSStringstringWithFormat:@"multipart/form-data; boundary=%@", boundary];

[requestsetValue:contentTypeforHTTPHeaderField:@"Content-Type"];

//设置请求头,告诉服务器本次长传的时文件信息//这一块的内容是不变的!

NSData*bodyData = [selfcreateBodyWithBoundary:boundaryparameters:dicpaths:@[filePath]fieldName:@"file"];

// 2.发送请求

NSURLSession*session = [NSURLSessionsharedSession];

NSURLSessionUploadTask*task = [sessionuploadTaskWithRequest:requestfromData:bodyDatacompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror) {

NSDictionary*responseObject = [NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingAllowFragmentserror:nil];

if(!responseObject ||0!= ((NSString*)responseObject[@"error_code"]).integerValue)

{

}

}];

//5 resume

[taskresume];

}

+ (NSData*)createBodyWithBoundary:(NSString*)boundary

parameters:(NSDictionary*)parameters

paths:(NSArray*)paths

fieldName:(NSString*)fieldName {

NSMutableData*httpBody = [NSMutableDatadata];

//文本参数

[parametersenumerateKeysAndObjectsUsingBlock:^(NSString*parameterKey,NSString*parameterValue,BOOL*stop) {

[httpBodyappendData:[[NSStringstringWithFormat:@"--%@\r\n", boundary]dataUsingEncoding:NSUTF8StringEncoding]];

[httpBodyappendData:[[NSStringstringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey]dataUsingEncoding:NSUTF8StringEncoding]];

[httpBodyappendData:[[NSStringstringWithFormat:@"%@\r\n", parameterValue]dataUsingEncoding:NSUTF8StringEncoding]];

}];

//本地文件的NSData

for(NSString*pathinpaths) {

NSString*filename=@"m4a";

NSData*data= [NSDatadataWithContentsOfFile:path];

NSString*mimetype= [selfmimeTypeForPath:path];

[httpBodyappendData:[[NSStringstringWithFormat:@"--%@\r\n", boundary]dataUsingEncoding:NSUTF8StringEncoding]];

[httpBodyappendData:[[NSStringstringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, filename]dataUsingEncoding:NSUTF8StringEncoding]];

[httpBodyappendData:[[NSStringstringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype]dataUsingEncoding:NSUTF8StringEncoding]];

[httpBodyappendData:data];

[httpBodyappendData:[@"\r\n"dataUsingEncoding:NSUTF8StringEncoding]];

}

[httpBodyappendData:[[NSStringstringWithFormat:@"--%@--\r\n", boundary]dataUsingEncoding:NSUTF8StringEncoding]];

returnhttpBody;

}

+ (NSString*)mimeTypeForPath:(NSString*)path {

CFStringRefextension = (__bridgeCFStringRef)[pathpathExtension];

CFStringRefUTI =UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension,NULL);

NSString*mimetype =CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI,kUTTagClassMIMEType));

CFRelease(UTI);

returnmimetype;

}

求打赏,请喝可乐~~~哈哈


AFNetWorking中适配iOS7的坑坑_第3张图片

你可能感兴趣的:(AFNetWorking中适配iOS7的坑坑)