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

查看:349
本文介绍了使用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>

我看了很多关于如何进行multipart / form-data POST的文章在iOS上,但没有一个真正解释如果有正常的参数以及文件上传该怎么办。

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. 使用 userName 创建字典, userEmail userPassword 参数。

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:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"%@\r\n", 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:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fieldName, filename] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimetype] dataUsingEncoding:NSUTF8StringEncoding]];
            [httpBody appendData:data];
            [httpBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
        }
    
        [httpBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", 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

    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天全站免登陆