解讀AF之AFHTTPSessionManager

介紹

AFNetworking作為iOS的網(wǎng)絡(luò)請求框架,其內(nèi)部是對iOS提供的NSURLSession進(jìn)行的封裝,從使用成面來說是非常方便的,它提供了一套非常簡單的易用的接口.AFHTTPSessionManager 這個類是對外所有接口進(jìn)行的封裝,從類名來看,顧名思義,是基于HTTP協(xié)議進(jìn)行的網(wǎng)絡(luò)通信.下面來介紹AFHTTPSessionManager內(nèi)部的組成.

AFHTTPSessionManager

  1. HTTP協(xié)議是用于客戶端和服務(wù)端通信,HTTP通信過程包括從客戶端向服務(wù)器發(fā)出的請求,以及服務(wù)器返回客戶端的響應(yīng).
  2. 用于HTTP協(xié)議交互的信息稱為HTTP報文,請求端的HTTP報文叫做請求報文,響應(yīng)端的叫做響應(yīng)報文.
  3. 請求報文
  • 請求行:說明請求類型,要訪問的資源,以及使用的HTTP版本
  • 請求頭:說明服務(wù)器要使用的附加信息(鍵值對組成).
  • 空行: 空行是必須要存在的,因為他是請求報文的一部分
  • 請求數(shù)據(jù): 通常也叫請求報文的主體,可以添加任意的數(shù)據(jù).
  1. 響應(yīng)報文
  • 狀態(tài)行:包括HTTP協(xié)議版本號,狀態(tài)碼,狀態(tài)信息.
  • 消息報文:說明客戶端要使用的一些附加信息
  • 空行:空行是必須要存在的,因為他是響應(yīng)報文的一部分.
  • 響應(yīng)正文: 服務(wù)器返回給客戶端的文本信息.

在請求報文中,請求類型主要指的是HTTP支持的幾種不同的請求命令,這些命令也叫做請求方法.

下面列舉一些常見的請求方法.

http方法 描述
GET 從服務(wù)器向客戶端發(fā)送命名資源
POST 將客戶端數(shù)據(jù)發(fā)送到一個服務(wù)器網(wǎng)關(guān)應(yīng)用程序
PUT 將來自客戶端的數(shù)據(jù)存儲到一個命名服務(wù)器資源中去
DELETE 從服務(wù)器中刪除命名資源
HEAD 僅發(fā)送命名資源響應(yīng)中的HTTP首部

關(guān)于對HTTP協(xié)議這里只是粗略的介紹,關(guān)鍵是介紹HTTP的請求方法有哪些,如果詳細(xì)了解HTTP協(xié)議,請查看相應(yīng)的資料
針對上述的介紹我們知道了HTTP協(xié)議的請求方法有哪些,在AF中對這些方法做了相應(yīng)的接口封裝.

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;

關(guān)于上述的請求這里就不過多的介紹了,因為在AFHTTPSessionManager中核心方法是

// 所有的請求方法都會進(jìn)入這個方法 --- 返回一個請求任務(wù)
- (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;
    
    // 對請求報文首部進(jìn)行參數(shù)拼接完成之后的一個請求
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    
    // 如果參數(shù) headers 有值 那么就在對請求頭進(jìn)行設(shè)置
    for (NSString *headerField in headers.keyEnumerator) {
        [request addValue:headers[headerField] forHTTPHeaderField:headerField];
    }
    
    // 如果發(fā)生錯誤,異步返回錯誤, self.completionQueue 默認(rèn)隊列是NULL,會使用主隊列,這個參數(shù)的意義是提供給外界自行定義,在什么隊列中返回錯誤信息.
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }

        return nil;
    }

    // 根據(jù)請求返回一個任務(wù)
    __block NSURLSessionDataTask *dataTask = nil;
    
    // 基類調(diào)用父類封裝的方法,獲取一個請求任務(wù).
    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進(jìn)行的封裝.

也就是說該方法調(diào)用父類AFURLSessionManagerdataTaskWithRequest:是解讀的關(guān)鍵.關(guān)于對AFURLSessionManager的解讀,下一篇文章有詳細(xì)的介紹.這里先介紹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];
    }
    
    //序列化異常,默認(rèn)異步主隊列返回
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }
        return nil;
    }
    // 調(diào)用父類的方法,返回一個上傳任務(wù)
    __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);
            }
        }
    }];
    
    // 開啟上傳任務(wù)
    [task resume];
    
    return task;
}

總結(jié)

不管是參數(shù)請求還是文件上傳,常規(guī)的套路就是:創(chuàng)建請求,獲取任務(wù),開始任務(wù).這三部分,其實這和系統(tǒng)調(diào)用的接口順序是差不多的,需要值得注意的是,參數(shù)請求和文件上傳時不一樣的,在使用層面上來說,使用起來很簡單,接口調(diào)用也不是很復(fù)雜,AF框架中針對提供的結(jié)構(gòu)也提供了相應(yīng)的測試案例,這個框架對于學(xué)習(xí)來說是非常不錯的.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容