代码改变世界

iOS开发系列-文件上传

2018-04-21 11:48  iCoderHong  阅读(2809)  评论(0编辑  收藏  举报

概述

Http协议对文件上传协议要求的
1. 必须设置请求头Content-Type为multipart/form-data。在iOS中后面需要跟上分隔符比如:boundary=----WebKitFormBoundaryDYeXSvJz9Yuyf6Du。分割可以任意字符

2. 上传的参数是有要求的,具体的数据格式如下

如果请求头没有设置Content-Type为multipart/form-data则为普通的POST请求。

文件上传

通过NSURLConnection上传文件

#define FMDataWithString(Str) [Str dataUsingEncoding:NSUTF8StringEncoding]
#define FMNewLine FMDataWithString(@"\r\n")

// #define FMSeparator @"----WebKitFormBoundaryt8fVxWuv0hn9uOjt" 分隔符

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    // 设置POST请求
    request.HTTPMethod = @"POST";
    // 上传的请求头必须参数设置
    [request setValue:@"multipart/form-data; boundary=----WebKitFormBoundaryt8fVxWuv0hn9uOjt" forHTTPHeaderField:@"Content-Type"];
    
    // 处理请求体
    request.HTTPBody = [self handleHttpBody];
    
    
    // 发送请求
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        
        NSLog(@"-------------%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }];
    
}

- (NSMutableData *)handleHttpBody
{
    NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"Snip20180325_5"], 1.0);
    
    NSMutableData *httpBodyData = [NSMutableData data];
    
    [httpBodyData appendData:FMDataWithString(@"------WebKitFormBoundaryt8fVxWuv0hn9uOjt")]; [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:FMDataWithString(@"Content-Disposition: form-data; name=\"file\"; filename=\"Snip20180325_11.png\"")]; [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:FMDataWithString(@"Content-Type: image/png")]; [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:imageData]; [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:FMNewLine];
    
    // 非文件参数
    [httpBodyData appendData:FMDataWithString(@"------WebKitFormBoundaryt8fVxWuv0hn9uOjt")]; [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:FMDataWithString(@"Content-Disposition: form-data; name=\"username\"")]; [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:FMNewLine];
    [httpBodyData appendData:FMDataWithString(@"tom")]; [httpBodyData appendData:FMNewLine];
    
    // 结束分隔符
    [httpBodyData appendData:FMDataWithString(@"------WebKitFormBoundaryt8fVxWuv0hn9uOjt--")];
    
    return httpBodyData;
}
@end

NSURLSession上传文件

使用NSURLSession上传文件跟NSURLConnection对比两者步骤差不多,只是请求体的位置不一样。NSURLConnection数据是放在request中。NSURLSession放在参数中;

NSURLSessionUploadTask *task = [[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:[self handleHttpBody] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"-------------%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];

AFNetworking文件上传

NSDictionary *param = @{@"username": @"CoderHong"};
    [[AFHTTPSessionManager manager] POST:@"http://120.25.226.186:32812/upload" parameters:param constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        /**
         设置需要上传的文件
         @param name 服务器字段名
         @param fileName 要传递的文件名
         @param mimeType 文件的mimetype
         */
        [formData appendPartWithFileData:UIImageJPEGRepresentation([UIImage imageNamed:@"Snip20180325_5"], 1.0) name:@"file" fileName:@"Snip20180325_5.png" mimeType:@"image/png"];
        
        // 通过传递文件的路径
        // [formData appendPartWithFileURL:[NSURL fileURLWithPath:@""] name:@"file" fileName:@"Snip20180325_5" mimeType:@"image/png" error:nil];
        // [formData appendPartWithFileURL:[NSURL fileURLWithPath:@""] name:@"file" error:nil];
        
    } progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"-----------%@", responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
    }];