您的位置:首页 > 移动开发 > IOS开发

iOS使用表单流上传文件(图片/文本/...)

2017-02-21 14:41 501 查看
开篇,先安利一下关于POST与GET这两种请求方式在使用过程中应该知道的优缺点,是知乎里面的一个问题讨论。【POST相比GET有很多优点,为什么现在的HTTP通信中大多数请求还是使用GET?】

#define HTTP_CONTENT_BOUNDARY @"----WebKitFormBoundarywpMAGHPPMfSNBkkK----"

+ (BOOL)httpPutDataWithUploadDate:(NSString *)uploadDate UserName:(NSString *)userName FilePath:(NSString *)filePath{

NSString *strUrl = [clsOtherFun getUploadCrashFileURL];
strUrl = [strUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSURL *url = [NSURL URLWithString:strUrl];
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSString *fileName = [filePath lastPathComponent];

NSMutableString *bodyStr = [[NSMutableString alloc] init];
[bodyStr appendString:[NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"UploadDate\";\n\n%@\n", HTTP_CONTENT_BOUNDARY, uploadDate]];
[bodyStr appendString:[NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"UserName\";\n\n%@\n", HTTP_CONTENT_BOUNDARY, userName]];
[bodyStr appendString:[NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"System\";\n\niOS\n", HTTP_CONTENT_BOUNDARY]];
[bodyStr appendString:[NSString stringWithFormat:@"--%@\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\nContent-Type: %@\n\n",HTTP_CONTENT_BOUNDARY, @"file1",  fileName, @"text/plain"]];

NSMutableData *httpBody = [NSMutableData data];
[httpBody appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:data];
[httpBody appendData:[[NSString stringWithFormat:@"\n--%@",HTTP_CONTENT_BOUNDARY] dataUsingEncoding:NSUTF8StringEncoding]];

NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] init];
[urlRequest setURL:url];
[urlRequest setHTTPMethod:@"POST"];
[urlRequest setTimeoutInterval: 60000];
[urlRequest setValue:[NSString stringWithFormat:@"%@", @(httpBody.length)] forHTTPHeaderField:@"Content-Length"];
[urlRequest setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",HTTP_CONTENT_BOUNDARY] forHTTPHeaderField:@"Content-Type"];
urlRequest.HTTPBody = httpBody;

NSHTTPURLResponse *httpResponse = nil;
NSError *error = [[NSError alloc] init];
NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&httpResponse error:&error];

if (responseData != nil) {
//        NSMutableDictionary *dict = NULL;
//IOS5自带解析类NSJSONSerialization从response中解析出数据放到字典中
//        NSString *responseStr = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];

//若状态码为200,则服务器访问成功!
if (httpResponse == nil) {
NSLog(@"url: %@\nerror_code: %@", strUrl, error);
}
if (httpResponse.statusCode != 200) {
NSLog(@"url: %@\nHTTP response: %ld", strUrl, (long)httpResponse.statusCode);
}

//若后台返回字符串“1”,则文件上传成功!
NSString *resultStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if (httpResponse.statusCode == 200 && [resultStr isEqualToString:@"1"]) {
return YES;
}
else{
return NO;
}

NSLog(@"upload_file_resultStr: %@", resultStr);

}

return NO;
}


这是我用Safari截取的POST请求的表单流格式,见下图:



(因后台服务器提供的接口已不可访问,故显示的内容不太契合。若访问正常,则“No user permission.”显示为下图的内容。)



上面就是需要拼接的表单流格式。注意:一定要严格遵循这种格式!

图中每个框框的内容为对应参数的格式。

这时候只需要我们拼接的参数、字符串格式是严格遵循以上格式。



上面的代码不免显得臃肿,也难以通用。

下面介绍一种更为简单便捷的方式,当然同样基于POST请求。没错,主角就是AFNetworking,AFHTTPSessionManager为我们提供了

*- (NSURLSessionDataTask )POST:(NSString *)URLString

parameters:(id)parameters

constructingBodyWithBlock:(void (^)(id formData))block

progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress

success:(void (^)(NSURLSessionDataTask *task, id responseObject))success

failure:(void (^)(NSURLSessionDataTask task, NSError *error))failure*

这一方法,自从用了它,我们的代码处理一切都变得简单起来。

关键代码:

AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
session.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:
@"application/json",
@"text/json",
@"text/javascript",
@"text/html",
@"text/plain",
nil];
[session POST:[Utils getVerificationURL]
//我们的参数集合
parameters:@{@"UserID":userIDStr,
@"IDNumber":idNumStr,
@"RealName":realNameStr,
@"File1":fileName1,
@"File2":fileName2}
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:photoData1 name:@"File1"
fileName:fileName1 mimeType:@"image/jpeg"];
[formData appendPartWithFileData:photoData2 name:@"File2"
fileName:fileName2 mimeType:@"image/jpeg"];

}
progress:^(NSProgress * _Nonnull uploadProgress) {
NSLog(@"service progress...");
}
success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
if (responseObject != nil) {

// {"Code":1,"Msg":"1.成功; 3.用户不存在或无效; 4.用户已经完成审核;  5.写入数据失败 "}
// 若后台返回"Code"字段为“1”,则文件上传成功!
NSLog(@"POST Response Code:%@", [responseObject valueForKey:@"Code"]);
//responseObject的格式已经为JSON数据格式。
if ([[responseObject valueForKey:@"Code"] integerValue] == 1){
//do you what you want.
//[session invalidateSessionCancelingTasks:YES];
}
}
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"POST Error: %@", error.description);
}
];
}


文章难免会有纰漏之处,若有发现,还望各位同仁提出。让我们共同交流,一起进步!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息