使用 Objective-C POST 多部分/表单数据 [英] POST multipart/form-data with Objective-C

查看:38
本文介绍了使用 Objective-C POST 多部分/表单数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以这个 HTML 代码以正确的格式提交数据给我.

So this HTML code submits the data in the correct format for me.

<form action="https://www.example.com/register.php" method="post" enctype="multipart/form-data">
    Name: <input type="text" name="userName"><BR />
    Email: <input type="text" name="userEmail"><BR />
    Password: <input type="text" name="userPassword"><BR />
    Avatar: <input type="file" name="avatar"><BR />
    <input type="submit">
</form>

我查阅了大量关于如何在 iOS 上进行多部分/表单数据 POST 的文章,但没有一篇文章真正解释了在正常参数和文件上传的情况下该怎么做.

I've looked into a good number of articles on how to do a multipart/form-data POST on iOS, but none really explain what to do if there were normal parameters as well as the file upload.

你能帮我在 Obj-C 中发布这个代码吗?

Could you please help me with the code to POST this in Obj-C?

谢谢!

推荐答案

流程如下:

  1. 使用userNameuserEmailuserPassword 参数创建字典.

  1. Create dictionary with the userName, userEmail, and userPassword parameters.

NSDictionary *params = @{@"userName"     : @"rob",
                         @"userEmail"    : @"rob@email.com",
                         @"userPassword" : @"password"};

  • 确定图像的路径:

  • Determine the path for the image:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"];
    

  • 创建请求:

  • Create the request:

    NSString *boundary = [self generateBoundaryString];
    
    // configure the request
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    [request setHTTPMethod:@"POST"];
    
    // set content type
    
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
    [request setValue:contentType forHTTPHeaderField: @"Content-Type"];
    
    // create body
    
    NSData *httpBody = [self createBodyWithBoundary:boundary parameters:params paths:@[path] fieldName:fieldName];
    

  • 这是上面用来构建请求正文的方法:

  • This is the method used above to build the body of the request:

    - (NSData *)createBodyWithBoundary:(NSString *)boundary
                            parameters:(NSDictionary *)parameters
                                 paths:(NSArray *)paths
                             fieldName:(NSString *)fieldName {
        NSMutableData *httpBody = [NSMutableData data];
    
        // add params (all params are strings)
    
        [parameters enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) {
            [httpBody appendData:[[NSString stringWithFormat:@"--%@
    ", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"
    
    ", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"%@
    ", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]];
        }];
    
        // add image data
    
        for (NSString *path in paths) {
            NSString *filename  = [path lastPathComponent];
            NSData   *data      = [NSData dataWithContentsOfFile:path];
            NSString *mimetype  = [self mimeTypeForPath:path];
    
            [httpBody appendData:[[NSString stringWithFormat:@"--%@
    ", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"; filename="%@"
    ", fieldName, filename] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@
    
    ", mimetype] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:data];
            [httpBody appendData:[@"
    " dataUsingEncoding:NSUTF8StringEncoding]];
        }
    
        [httpBody appendData:[[NSString stringWithFormat:@"--%@--
    ", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
        return httpBody;
    }
    

  • 以上使用了以下实用方法:

  • The above uses the following utility methods:

    @import MobileCoreServices;    // only needed in iOS
    
    - (NSString *)mimeTypeForPath:(NSString *)path {
        // get a mime type for an extension using MobileCoreServices.framework
    
        CFStringRef extension = (__bridge CFStringRef)[path pathExtension];
        CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);
        assert(UTI != NULL);
    
        NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType));
        assert(mimetype != NULL);
    
        CFRelease(UTI);
    
        return mimetype;
    }
    
    - (NSString *)generateBoundaryString {
        return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
    }
    

  • 然后提交请求.这里有很多很多选择.

  • Then submit the request. There are many, many options here.

    例如,如果使用NSURLSession,你可以创建NSURLSessionUploadTask:

    For example, if using NSURLSession, you could create NSURLSessionUploadTask:

    NSURLSession *session = [NSURLSession sharedSession];  // use sharedSession or create your own
    
    NSURLSessionTask *task = [session uploadTaskWithRequest:request fromData:httpBody completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"error = %@", error);
            return;
        }
    
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"result = %@", result);
    }];
    [task resume];
    

    或者你可以创建一个 NSURLSessionDataTask:

    Or you could create a NSURLSessionDataTask:

    request.HTTPBody = httpBody;
    
    NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"error = %@", error);
            return;
        }
    
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"result = %@", result);
    }];
    [task resume];
    

    以上假设服务器只是返回文本响应.如果服务器返回 JSON 会更好,在这种情况下,您应该使用 NSJSONSerialization 而不是 NSString 方法 initWithData.

    The above assumes that the server is just returning text response. It's better if the server returned JSON, in which case you'd use NSJSONSerialization rather than NSString method initWithData.

    同样,我正在使用上述 NSURLSession 的完成块再现,但也可以随意使用更丰富的基于委托的再现.但这似乎超出了这个问题的范围,所以我将把它留给你.

    Likewise, I'm using the completion block renditions of NSURLSession above, but feel free to use the richer delegate-based renditions, too. But that seems beyond the scope of this question, so I'll leave that to you.

    但希望这能说明这个想法.

    But hopefully this illustrates the idea.

    如果我没有指出这一点,我会失职,比上面的要容易得多,你可以使用 AFNetworking,重复上面的第 1 步和第 2 步,然后只是调用:

    I'd be remiss if I didn't point that, much easier than the above, you can use AFNetworking, repeating steps 1 and 2 above, but then just calling:

    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // only needed if the server is not returning JSON; if web service returns JSON, remove this line
    NSURLSessionTask *task = [manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
        NSError *error;
        if (![formData appendPartWithFileURL:[NSURL fileURLWithPath:path] name:@"avatar" fileName:[path lastPathComponent] mimeType:@"image/png" error:&error]) {
            NSLog(@"error appending part: %@", error);
        }
    }  progress:nil success:^(NSURLSessionTask *task, id responseObject) {
        NSLog(@"responseObject = %@", responseObject);
    } failure:^(NSURLSessionTask *task, NSError *error) {
        NSLog(@"error = %@", error);
    }];
    
    if (!task) {
        NSLog(@"Creation of task failed.");
    }
    

    这篇关于使用 Objective-C POST 多部分/表单数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆