解读AF之AFHTTPSessionManager

2019-02-05  本文已影响0人  Mr_DML

介绍

AFNetworking作为iOS的网络请求框架,其内部是对iOS提供的NSURLSession进行的封装,从使用成面来说是非常方便的,它提供了一套非常简单的易用的接口.AFHTTPSessionManager 这个类是对外所有接口进行的封装,从类名来看,顾名思义,是基于HTTP协议进行的网络通信.下面来介绍AFHTTPSessionManager内部的组成.

AFHTTPSessionManager

  1. HTTP协议是用于客户端和服务端通信,HTTP通信过程包括从客户端向服务器发出的请求,以及服务器返回客户端的响应.
  2. 用于HTTP协议交互的信息称为HTTP报文,请求端的HTTP报文叫做请求报文,响应端的叫做响应报文.
  3. 请求报文
  • 请求行:说明请求类型,要访问的资源,以及使用的HTTP版本
  • 请求头:说明服务器要使用的附加信息(键值对组成).
  • 空行: 空行是必须要存在的,因为他是请求报文的一部分
  • 请求数据: 通常也叫请求报文的主体,可以添加任意的数据.
  1. 响应报文
  • 状态行:包括HTTP协议版本号,状态码,状态信息.
  • 消息报文:说明客户端要使用的一些附加信息
  • 空行:空行是必须要存在的,因为他是响应报文的一部分.
  • 响应正文: 服务器返回给客户端的文本信息.

在请求报文中,请求类型主要指的是HTTP支持的几种不同的请求命令,这些命令也叫做请求方法.

下面列举一些常见的请求方法.

http方法 描述
GET 从服务器向客户端发送命名资源
POST 将客户端数据发送到一个服务器网关应用程序
PUT 将来自客户端的数据存储到一个命名服务器资源中去
DELETE 从服务器中删除命名资源
HEAD 仅发送命名资源响应中的HTTP首部

关于对HTTP协议这里只是粗略的介绍,关键是介绍HTTP的请求方法有哪些,如果详细了解HTTP协议,请查看相应的资料
针对上述的介绍我们知道了HTTP协议的请求方法有哪些,在AF中对这些方法做了相应的接口封装.

Snip20190205_1.png

我们看到上图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进行的封装.

也就是说该方法调用父类AFURLSessionManagerdataTaskWithRequest:是解读的关键.关于对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框架中针对提供的结构也提供了相应的测试案例,这个框架对于学习来说是非常不错的.

上一篇下一篇

猜你喜欢

热点阅读