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

<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上发布多部分/表单数据的文章,但没有一篇真正解释如果有正常参数以及文件上传,该怎么做.

你能帮我把代码发到Obj-C上吗?

谢谢

推荐答案

过程如下:

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

    NSDictionary *params = @{@"userName"     : @"rob",
                             @"userEmail"    : @"rob@email.com",
                             @"userPassword" : @"password"};
    
  2. 确定图像的路径:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"];
    
  3. 创建请求:

    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];
    
  4. 这是上面用于构建请求主体的方法:

    - (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;
    }
    
  5. 以上使用以下实用方法:

    @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]];
    }
    
  6. 然后提交请求.这里有很多很多 Select .

    例如,如果使用NSURLSession,可以创建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.

    同样,我使用的是NSURLSession以上的完整块格式副本,但也可以使用更丰富的基于代理的格式副本.但这似乎超出了这个问题的范围,所以我将把这个问题留给你们.

但希望这能说明这个 idea .


如果我没有指出,你可以使用AFNetworking,重复上面的第一步和第二步,但只需调用:

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相关问答推荐

在没有for循环的情况下获取另一个数组中每个对象的属性值数组

如何向 UILabel 添加滚动功能

常量的 k 前缀从何而来?

对 nil 对象进行快速枚举

Facebook 添加测试用户和管理员是:(待定),这是什么意思?

在Objective-C中从类名的NSString创建对象

UICollectionView 标头未显示

CF 对象与 NS 对象

iOS 在设备旋转时更改自动布局约束

在 Cocoa 中你更喜欢 NSInteger 还是 int,为什么?

OSStatus 错误代码 -34018

设置数据后调整 UICollectionView 单元格的大小

'supportedInterfaceOrientations' 实现中的返回类型冲突: - 警告

NS_ASSUME_NONNULL_BEGIN 宏

-[MyClassName copyWithZone:] 无法识别的 Select 器发送到实例

Objective-C 中的 NSString indexOf

如何为 iPhone 6/7 自定义边到边图像指定尺寸?

为什么 Select Emacs/Vim/Textmate? Xcode 还不够好吗?

字符串常量和字符串文字有什么区别?

UITableViewCell中的文本居中对齐问题