解读AF之AFHTTPSessionManager
介绍
AFNetworking作为iOS的网络请求框架,其内部是对iOS提供的NSURLSession
进行的封装,从使用成面来说是非常方便的,它提供了一套非常简单的易用的接口.AFHTTPSessionManager
这个类是对外所有接口进行的封装,从类名来看,顾名思义,是基于HTTP协议进行的网络通信.下面来介绍AFHTTPSessionManager
内部的组成.
AFHTTPSessionManager
- HTTP协议是用于客户端和服务端通信,HTTP通信过程包括从客户端向服务器发出的请求,以及服务器返回客户端的响应.
- 用于HTTP协议交互的信息称为HTTP报文,请求端的HTTP报文叫做请求报文,响应端的叫做响应报文.
- 请求报文
- 请求行:说明请求类型,要访问的资源,以及使用的HTTP版本
- 请求头:说明服务器要使用的附加信息(键值对组成).
- 空行: 空行是必须要存在的,因为他是请求报文的一部分
- 请求数据: 通常也叫请求报文的主体,可以添加任意的数据.
- 响应报文
- 状态行:包括HTTP协议版本号,状态码,状态信息.
- 消息报文:说明客户端要使用的一些附加信息
- 空行:空行是必须要存在的,因为他是响应报文的一部分.
- 响应正文: 服务器返回给客户端的文本信息.
在请求报文中,请求类型主要指的是HTTP支持的几种不同的请求命令,这些命令也叫做请求方法.
下面列举一些常见的请求方法.
http方法 | 描述 |
---|---|
GET | 从服务器向客户端发送命名资源 |
POST | 将客户端数据发送到一个服务器网关应用程序 |
PUT | 将来自客户端的数据存储到一个命名服务器资源中去 |
DELETE | 从服务器中删除命名资源 |
HEAD | 仅发送命名资源响应中的HTTP首部 |
关于对HTTP协议这里只是粗略的介绍,关键是介绍HTTP的请求方法有哪些,如果详细了解HTTP协议,请查看相应的资料
针对上述的介绍我们知道了HTTP协议的请求方法有哪些,在AF中对这些方法做了相应的接口封装.
我们看到上图AFHTTPSessionManager
继承AFURLSessionManager
在AFHTTPSessionManager
中提供了一些常用的请求方法
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
success:(nullable void (^)(NSURLSessionDataTask *task))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
// 上传文件请求
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
关于上述的请求这里就不过多的介绍了,因为在AFHTTPSessionManager
中核心方法是
// 所有的请求方法都会进入这个方法 --- 返回一个请求任务
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
headers:(NSDictionary <NSString *, NSString *> *)headers
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
NSError *serializationError = nil;
// 对请求报文首部进行参数拼接完成之后的一个请求
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
// 如果参数 headers 有值 那么就在对请求头进行设置
for (NSString *headerField in headers.keyEnumerator) {
[request addValue:headers[headerField] forHTTPHeaderField:headerField];
}
// 如果发生错误,异步返回错误, self.completionQueue 默认队列是NULL,会使用主队列,这个参数的意义是提供给外界自行定义,在什么队列中返回错误信息.
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
// 根据请求返回一个任务
__block NSURLSessionDataTask *dataTask = nil;
// 基类调用父类封装的方法,获取一个请求任务.
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
// 请求失败
if (failure) {
failure(dataTask, error);
}
} else {
// 请求成功
if (success) {
success(dataTask, responseObject);
}
}
}];
return dataTask;
}
上述的请求接口除了文件上传接口,都是对dataTaskWithHTTPMethod
进行的封装.
也就是说该方法调用父类AFURLSessionManager
的dataTaskWithRequest:
是解读的关键.关于对AFURLSessionManager
的解读,下一篇文章有详细的介绍.这里先介绍AF提供对外的接口类AFHTTPSessionManager
简单使用,在该类中还有文件上传的方法.
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
headers:(NSDictionary<NSString *,NSString *> *)headers
constructingBodyWithBlock:(void (^)(id<AFMultipartFormData> _Nonnull))block
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
NSError *serializationError = nil;
// 获取一个拼接好的请求(文件上传请求)
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
// 拼接请求头
for (NSString *headerField in headers.keyEnumerator) {
[request addValue:headers[headerField] forHTTPHeaderField:headerField];
}
//序列化异常,默认异步主队列返回
if (serializationError) {
if (failure) {
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
return nil;
}
// 调用父类的方法,返回一个上传任务
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(task, error);
}
} else {
if (success) {
success(task, responseObject);
}
}
}];
// 开启上传任务
[task resume];
return task;
}
总结
不管是参数请求还是文件上传,常规的套路就是:创建请求,获取任务,开始任务.这三部分,其实这和系统调用的接口顺序是差不多的,需要值得注意的是,参数请求和文件上传时不一样的,在使用层面上来说,使用起来很简单,接口调用也不是很复杂,AF框架中针对提供的结构也提供了相应的测试案例,这个框架对于学习来说是非常不错的.