1 概述
AFHTTPSessionManager
是AFURLSessionManager
的子类。我们可以通过这个类做HTTP请求。其实整个AFHTTPSessionManager
逻辑很简单,只是用HTTP的方式拼接了请求,并且调用父类的方式做处理。我会通过AFHTTPSessionManager
api来讲一下POST上传数据的几种基本格式,然后我再随便分析一下AFHTTPSessionManager
。
2 POST请求的常用格式
HTTP/1.1协议规定的HTTP请求方法有OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。其中POST一般用来向服务端提交数据,接下来要讨论POST提交数据的几种方式。协议规定POST提交的数据必须放在消息主体中,但协议并没有规定数据必须使用什么编码方式。实际上,开发者完全可以自己决定消息主体的格式,只要最后发送的 HTTP 请求满足上面的格式就可以。
但是,数据发送出去,还要服务端解析成功才有意义。一般服务端语言如php、python等,以及它们的framework,都内置了自动解析常见数据格式的功能。服务端通常是根据请求头(headers)中的Content-Type字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到POST提交数据方案,包含了Content-Type和消息主体编码方式两部分。
2.1 application/x-www-form-urlencoded格式的POST请求
这应该是最常见的 POST 提交数据的方式了。浏览器的原生表单,如果不设置enctype属性,那么最终就会以application/x-www-form-urlencoded方式提交数据。Content-Type被指定为application/x-www-form-urlencoded,提交的数据按照 key1=val1&key2=val2的方式进行编码,key和val都进行了URL转码。
下面这个请求是简书进入一篇文章页面的时候,会自动往服务器POST一个请求,估计是统计文章被阅读的次数等功能。具体看下面:
//发送的请求,删除了cookie相关的部分
POST /notes/e15592ce40ae/mark_viewed.json HTTP/1.1
Host: www.jianshu.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
X-CSRF-Token: vJvptva4Tqou/V3dd3nFCrcvRsb78FReHuIYZke5PVAnfR/tIAAMCfuaB2Z2/gaEohIZAsiEksUYyPqzg3DpSA==
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://www.jianshu.com/p/e15592ce40ae
Content-Length: 98
Connection: keep-alive
Cache-Control: max-age=0
//请求体
uuid=4e3abc0f-1824-4a5d-982f-7d9dee92d9cd&referrer=http%3A%2F%2Fwww.jianshu.com%2Fu%2Fad726ba6935d
用AFHTTPSessionManager
实现上面这个application/x-www-form-urlencoded
请求。
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSDictionary *params = @{
@"uuid":@"4e3abc0f-1824-4a5d-982f-7d9dee92d9cd",
@"referrer":@"http://www.jianshu.com/p/e15592ce40ae"
};
NSURLSessionDataTask *task = [manager POST:@"http://www.jianshu.com//notes/e15592ce40ae/mark_viewed.json" parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
NSLog(@"进度更新");
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"返回数据:%@",responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"返回错误:%@",error);
}];
[task resume];
2.2 multipart/form-data格式的POST请求
Multipart/form-data的基础方法是POST , 也就是说是由POST方法来组合实现的.
Multipart/form-data与POST方法的不同之处在于请求头和请求体.
Multipart/form-data的请求头必须包含一个特殊的头信息 : Content-Type , 且其值也必须规定为multipart/form-data , 同时还需要规定一个内容分割符用于分割请求体中的多个POST的内容 , 如文件内容和文本内容自然需要分割开来 , 不然接收方就无法正常解析和还原这个文件了.
Multipart/form-data的请求体也是一个字符串 , 不过和post的请求体不同的是它的构造方式 , post是简单的name=value值连接 , 而Multipart/form-data则是添加了分隔符等内容的构造体.
请求的头部信息如下:
//其中xxxxx是我自定义的分隔符,每个人都可以选择自己的分隔符
Content-Type: multipart/form-data; boundary=xxxxx
下面我们来看一下一个我的Multipart/form-data请求体:
POST /uploadFile HTTP/1.1
Host: 这里是url,就不暴露了^_^
Content-Type: multipart/form-data; boundary=xxxxx
Connection: keep-alive
Accept: */*
User-Agent: AFNetWorking3.X%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/1 CFNetwork/808.2.16 Darwin/