AFNetworking3.1.0源码分析(七)详解AFHTTPRequestSerializer 之AFStreamingMultipartFormData上

本文主要介绍关于AFNetworking中对文件上传的处理,涉及到的知识点:

1:PUT 和 POST 方式的区别

2:http MIMEType  multipart/form-data

3:如何手动实现文件上传功能(使用iOS NSMutableRequest,NSURLConnection或者NSURLSession)的请求对象创建和配置

4:AFNetWorking 的封装实现提交诸如:文本、图片等数据到服务器即文件的上传功能的请求对象创建和配置

针对以上问题下面做详细的介绍:

1:PUT 和 POST  方式都可以用来向服务器提交数据,不同的是如果有多个请求发送,PUT会覆盖掉前面的所有请求执行的操作,而POST请求会执行多个不同的请求操作

2:multipart/form-data 是一种多用途formdata,普通的form表单提交数据不能提交文件类型的数据,所以multipart/form-data是一种对普通form表单提交数据的一种扩充,建立在普通的post请求至上的一种请求操作

3:如果手动实现文件的上传比如向服务器上传多张图片(本例子以上传两张png图片 :1.png,2.png)生成的请求体格式如下:

--tsunamierImageFlag
Content-Disposition: form-data; name="0"; filename=1.png
Content-Type: image/png

图片二进制数据
--tsunamierImageFlag
Content-Disposition: form-data; name="1"; filename=2.png
Content-Type: image/png

图片二进制数据
--tsunamierImageFlag--


以上格式需要转换成data详细步骤如下:

①:创建NSMutableRequest 对象:

NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:];

②:设置request请求头

NSString *BOUNDARY = @"tsunamierFileFlag";//此处的标识符对应着请求体中的标识
NSString *ContentType=[[NSString alloc]initWithFormat:@"multipart/form-data; boundary=%@",BOUNDARY];
[request setValue:ContentType forHTTPHeaderField:@"Content-Type"]
③:设置request请求体data数据:

NSArray *images = @[[UIImage imageNamed:@"1.png"],[UIImage imageNamed:@"2.png"]];
    NSArray *imageNames = @[@"1.png",@"2.png"];
    NSString *BOUNDARY = @"tsunamierImageFlag";
    //分界符号 --tsunamierFileFlag
    NSString *BoundarySingle=[[NSString alloc]initWithFormat:@"--%@",BOUNDARY];
    //结束符 --tsunamierFileFlag--
    NSString *endBoundary=[[NSString alloc]initWithFormat:@"%@--",BoundarySingle];
    
    NSMutableData *data = [[NSMutableData alloc] init];
    NSMutableString *str = [[NSMutableString alloc] init];
    for (int i = 0; i < [images count]; i++) {
        [str appendFormat:@"%@\r\n",BoundarySingle];
        [str appendFormat:@"Content-Disposition: form-data; name=\"%d\"; filename=%@\r\n",i,[imageNames objectAtIndex:i]];
        [str appendFormat:@"Content-Type: image/png\r\n\r\n"];
        [data appendData:[str dataUsingEncoding:NSUTF8StringEncoding]];
        NSData *imageData =UIImagePNGRepresentation([images objectAtIndex:i]);
        [data appendData:imageData];
        [data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    }
    NSString *end=[[NSString alloc]initWithFormat:@"%@%@",str,endBoundary];
    [data appendData:[end dataUsingEncoding:NSUTF8StringEncoding]];

4:详细介绍AFNetWorking实现设置request:

    4.1首先看下相关的类:

 


4.2 相关类的协作关系:

  


AFNEtworking 的使用例子:

NSString *filePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"logo" ofType:@"png"];
    UIImage *image = [UIImage imageWithContentsOfFile:filePath];
    
    NSData *data = UIImagePNGRepresentation(image);
    [self.manager
     POST:@"post"
     parameters:@{@"key":data}
     constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
         [formData appendPartWithFileData:[@"Data" dataUsingEncoding:NSUTF8StringEncoding]
                                     name:@"DataName"
                                 fileName:@"DataFileName"
                                 mimeType:@"data"];
     }
     progress:nil
     success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
         XCTAssertTrue([responseObject[@"files"][@"DataName"] isEqualToString:@"Data"]);
         XCTAssertTrue([responseObject[@"form"][@"key"] isEqual:data]);
         [expectation fulfill];
     }
     failure:nil];
使用Charles( 破解版)监听请求之后的数据( 在单元测试中将url scheme 改成http):

POST /post HTTP/1.1
Host: httpbin.org
Content-Type: multipart/form-data; boundary=Boundary+71B60CED9389BE5C
Connection: keep-alive
Accept: */*
User-Agent: (null)/(null) (iPhone; iOS 10.1; Scale/2.00) yi
Accept-Language: en;q=1
Content-Length: 21599
Accept-Encoding: gzip, deflate

--Boundary+71B60CED9389BE5C
Content-Disposition: form-data; name="key"

图片二进制数据
--Boundary+71B60CED9389BE5C
Content-Disposition: form-data; name="DataName"; filename="DataFileName"
Content-Type: data

Data
--Boundary+71B60CED9389BE5C--


可以看到在请求头结束之后的空两行就是请求体,使用分隔符隔离,此分隔符在 Content-Type字段已经给出,后端接受到数据之后根据此分隔符解析数据,因此所说multipart/form-data提供了能在请求体中使用多种类型的数据进行复合类型的请求,使用自定义分隔符标识每段请求内容,每个请求内容段都可以设置自己的:

Content-Type,Content-Disposition





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值