AFN表单上传图片
今天在做项目上传图片的时候,用到了formData上传图片,遇到了问题,很奇怪的问题。需求是这样的:
上传图片,首先压缩一定的比例,然后转成base64格式的data,传给后台参数是这样的:img_base64:imageData
在postMan中的请求是这样的:
在代码中,我们需要这样做,图片转码代码如下:
// 压缩图片质量
NSData *data = UIImageJPEGRepresentation(img, 0.5);
// 图片转码
NSData *dataImg = [data base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
- 算了,直接撸代码
// 1、创建请求管理者
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
mgr.responseSerializer = [AFHTTPResponseSerializer serializer];
mgr.requestSerializer = [AFHTTPRequestSerializer serializer];
AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
[securityPolicy setAllowInvalidCertificates:YES];
[mgr setSecurityPolicy:securityPolicy];
[mgr.requestSerializer setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[mgr.requestSerializer willChangeValueForKey:@"timeoutInterval"];
mgr.requestSerializer.timeoutInterval = 15.0f; // 默认超时时长为60s
[mgr.requestSerializer didChangeValueForKey:@"timeoutInterval"];
mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", @"multipart/form-data", @"application/json", @"text/html", @"image/jpeg", @"image/png", @"application/octet-stream", @"text/json", nil];
[mgr POST:URL parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
// 参数名:img_base64 :dataImg
[formData appendPartWithFormData:dataImg name:@"img_base64"];
} progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil];
self.responseObj = dict;
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[mgr.operationQueue cancelAllOperations];
SHOWERROR(@"识别失败");
}];
注意:在iOS转成base64的data的时候,是不带data:image/png;base64,这个头的,但是安卓在进行这些的时候是有的,所以需要跟后台商量好,踩坑了,以此谨记!
在AFN中还有另一种拼接方式,也是很常见的上传拼接方式
第二种方式
/**
POST请求(接收JSON格式数据)
@param URLString 请求的URL
@param parameters 请求的参数
@param photos 上传图片数组
@param success 请求成功的回调
@param failure 请求失败的回调
*/
- (void)POST:(NSString *)URLString parameters:(id)parameters photos:(NSArray *)photos success:(void (^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
// 1、创建请求管理者
AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
mgr.responseSerializer = [AFHTTPResponseSerializer serializer];
mgr.requestSerializer = [AFHTTPRequestSerializer serializer];
AFSecurityPolicy *securityPolicy = [[AFSecurityPolicy alloc] init];
[securityPolicy setAllowInvalidCertificates:YES];
[mgr setSecurityPolicy:securityPolicy];
[mgr.requestSerializer setValue:@"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[mgr.requestSerializer willChangeValueForKey:@"timeoutInterval"];
mgr.requestSerializer.timeoutInterval = 15.0f; // 默认超时时长为60s
[mgr.requestSerializer didChangeValueForKey:@"timeoutInterval"];
mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/plain", nil];
[mgr POST:URLString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
// formData: 专门用于拼接需要上传的数据,在此位置生成一个要上传的数据体
// 这里的_photoArr是你存放图片的数组
// formData: 专门用于拼接需要上传的数据,在此位置生成一个要上传的数据体
// 这里的_photoArr是你存放图片的数组
for (int i = 0; i < photos.count; i++) {
UIImage *image = photos[i];
//QFLog(@"+++++%@",image);
NSData *imageData = UIImagePNGRepresentation(image);
// 在网络开发中,上传文件时,是文件不允许被覆盖,文件重名
// 要解决此问题,
// 可以在上传时使用当前的系统事件作为文件名
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// 设置时间格式
[formatter setDateFormat:@"yyyyMMddHHmmss"];
NSString *dateString = [formatter stringFromDate:[NSDate date]];
NSString *fileName = [NSString stringWithFormat:@"%@%ld.png", dateString,(NSInteger)i];
/*
*该方法的参数
1. appendPartWithFileData:要上传的照片[二进制流]
2. name:对应网站上[upload.php中]处理文件的字段(比如upload)
3. fileName:要保存在服务器上的文件名
4. mimeType:上传的文件的类型
*/
[formData appendPartWithFileData:imageData name:@"file" fileName:fileName mimeType:@"application/octet-stream"]; //
}
} progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(responseObject);
}
[mgr.operationQueue cancelAllOperations];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
[mgr.operationQueue cancelAllOperations];
}];
}
系统方式
如果不用AFN的话,用系统的方法,就有点麻烦了,这里是系统的方法:
#pragma mark ------系统上传
- (void)uploadHeadImage:(UIImage *)image onSuccess:(void (^)(NSDictionary *dict))onSuccess onFailure:(void(^)(NSError *error))onFailure {
//BaseWebAddr:服务器地址
NSString *urlStr = @"http://47.104.193.88:8080/plant/recognize";
NSURL *url = [NSURL URLWithString:urlStr];
//在此声明一个字符串常量,代替下面的 BOUNDARY 字符串
// NSString * const POST_BOUNDS = @"----iOSKitFormBoundarycIO0B6mmsXU6koBg";
NSData *imageData;
NSString *imageFormat;
if (UIImagePNGRepresentation(image) != nil) {
imageFormat = @"Content-Type: image/png \r\n";
imageData = UIImagePNGRepresentation(image);
imageData = [imageData base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
}else{
imageFormat = @"Content-Type: image/jpeg \r\n";
imageData = UIImageJPEGRepresentation(image, 1.0);
imageData = [imageData base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
//设置请求实体
NSMutableData *body = [NSMutableData data];
///文件参数
[body appendData:[self getDataWithString:@"--BOUNDARY\r\n" ]];
NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"pppp.jpg\"\r\n",@"img_base64"];
[body appendData:[self getDataWithString:disposition]];
[body appendData:[self getDataWithString:imageFormat]];
[body appendData:[self getDataWithString:@"\r\n"]];
[body appendData:imageData];
[body appendData:[self getDataWithString:@"\r\n"]];
//普通参数
[body appendData:[self getDataWithString:@"--BOUNDARY\r\n" ]];
//上传参数需要key
NSString *dispositions = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n",@"uid"];
[body appendData:[self getDataWithString:dispositions]];
[body appendData:[self getDataWithString:@"\r\n"]];
[body appendData:[self getDataWithString:@"\r\n"]];
//参数结束
[body appendData:[self getDataWithString:@"--BOUNDARY--\r\n"]];
request.HTTPBody = body;
//设置请求体长度
NSInteger length = [body length];
[request setValue:[NSString stringWithFormat:@"%ld",length] forHTTPHeaderField:@"Content-Length"];
//设置 POST请求文件上传
[request setValue:@"multipart/form-data; boundary=BOUNDARY" forHTTPHeaderField:@"Content-Type"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSJSONSerialization *object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSDictionary *dict = (NSDictionary *)object;
NSLog(@"=====%@",[dict objectForKey:@"success"]);
}];
//开始任务
[dataTask resume];
}
-(NSData *)getDataWithString:(NSString *)string{
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
return data;
}
这里的参数是img_base64:imageData uid:uid
本人也是在踩坑的路上不断前进,希望对大家有用