使用post方法上传文件的两种做法

戴维营教育原创文章,转载请注明出处。我们的梦想是做最好的iOS开发培训!

项目需要使用HTTP协议中的POST方法上传文件,稍微总结了一下,将过程贴出来,方便以后参考。有两种方法,第一是使用NSMutableURLRequest完全从零开始设置,可以加深对HTTP协议的理解;第二种是直接使用别人封装好的代码,如AFNetworking。

方法一,从0开始文件上传

NSURL *url = [NSURL URLWithString:@"http://yo.diveinedu.com/upload.php"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";

//0. 设置分隔符
NSString *boundary = @"a1b2c3d4e5f6";
[request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] forHTTPHeaderField:@"Content-Type"];

NSLog(@"%@", request.allHTTPHeaderFields);

NSMutableData *httpBody = [NSMutableData data];
//1. 开始的分隔符
[httpBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

//2. 设置内容: 标签名,文件名等
[httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"fileToUpload\"; filename=\"%@\"\r\n", @"mask0.png"] dataUsingEncoding:NSUTF8StringEncoding]];

NSString *path = [[NSBundle mainBundle] pathForResource:@"mask0" ofType:@"png"];
NSLog(@"%@", [self typeForPath:path]);

//3. 设置内容格式
[httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", [self typeForPath:path]] dataUsingEncoding:NSUTF8StringEncoding]];

NSString *body = [[NSString alloc] initWithData:httpBody encoding:NSUTF8StringEncoding];
NSLog(@"%@", body);

//4. 添加真正的内容
NSData *data = [NSData dataWithContentsOfFile:path];
[httpBody appendData:data];

//5. 添加结束边界
[httpBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

//6. 设置http body
request.HTTPBody = httpBody;

//7. 发送请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@", str);
}];

重点:

  1. 注意协议中需要使用回车换行(\r\n)的位置,HTTP是一个基于文本行的协议,通过回车换行来控制格式。
  2. 注意分隔符(Boundary)的设置,尤其是(--)的增加。

设置后的内容应该是下面的样子(为了看得更清楚,将回车换行用文字表示出来了):

POST /upload.php HTTP/1.1\r\n
Host: yo.diveinedu.com\r\n
Content-Type: multipart/form-data; boundary=abcdefghigk\r\n
\r\n
Content-Disposition: form-data; name="fileToUpload"; filename="mask0.png"\r\n
Content-Type: image/png\r\n
\r\n--abcdefghigk\r\n
图片数据
\r\n--abcdefghigk--\r\n

方法二,使用AFNetworking中的方法

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager POST:@"http://yo.diveinedu.com/upload.php" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    //1. 方法一
//        NSError *error;
//        if (![formData appendPartWithFileURL:[NSURL fileURLWithPath:path] name:@"fileToUpload" fileName:[path lastPathComponent] mimeType:@"image/png" error:&error]) {
//            NSLog(@"error appending part: %@", error);
//        }

    //2. 方法二
    NSData *data = [NSData dataWithContentsOfFile:path];
    [formData appendPartWithFileData:data name:@"fileToUpload" fileName:[path lastPathComponent] mimeType:@"image/png"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSData *data = (NSData *)responseObject;
    NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"%@", str);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"%@", error);
}];

进行网络编程的时候,可以使用Wireshark之类的抓包工具辅助调试。可以很明确的看到发送或接收的数据是否正确。

最后祝大家儿童节快乐~~~

戴维营学院(高级开发视频): http://v.diveinedu.com

潜心俱乐部(iOS面试必备): http://divein.club