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

开篇,先安利一下关于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);
                  }
             ];
        }

文章难免会有纰漏之处,若有发现,还望各位同仁提出。让我们共同交流,一起进步!

猜你喜欢

转载自blog.csdn.net/jingfa1993/article/details/56282438