解讀AF之AFHTTPSessionManager

介紹

AFNetworking作為iOS的網(wǎng)絡(luò)請求框架,其內(nèi)部是對iOS提供的NSURLSession進行的封裝,從使用成面來說是非常方便的,它提供了一套非常簡單的易用的接口.AFHTTPSessionManager 這個類是對外所有接口進行的封裝,從類名來看,顧名思義,是基于HTTP協(xié)議進行的網(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的請求方法有哪些,如果詳細了解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中核心方法是

// 所有的請求方法都會進入這個方法 --- 返回一個請求任務(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;
    
    // 對請求報文首部進行參數(shù)拼接完成之后的一個請求
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    
    // 如果參數(shù) headers 有值 那么就在對請求頭進行設(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進行的封裝.

也就是說該方法調(diào)用父類AFURLSessionManagerdataTaskWithRequest:是解讀的關(guān)鍵.關(guān)于對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];
    }
    
    //序列化異常,默認(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)系作者
  • 序言:七十年代末传透,一起剝皮案震驚了整個濱河市速梗,隨后出現(xiàn)的幾起案子酣栈,更是在濱河造成了極大的恐慌,老刑警劉巖次询,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異栖袋,居然都是意外死亡叹卷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門绅作,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芦圾,“玉大人,你說我怎么就攤上這事俄认「錾伲” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵眯杏,是天一觀的道長夜焦。 經(jīng)常有香客問我,道長岂贩,這世上最難降的妖魔是什么茫经? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮萎津,結(jié)果婚禮上卸伞,老公的妹妹穿的比我還像新娘。我一直安慰自己锉屈,他們只是感情好荤傲,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著颈渊,像睡著了一般遂黍。 火紅的嫁衣襯著肌膚如雪终佛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天雾家,我揣著相機與錄音查蓉,去河邊找鬼。 笑死榜贴,一個胖子當(dāng)著我的面吹牛豌研,可吹牛的內(nèi)容都是我干的唬党。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼驶拱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蓝纲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤税迷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后箭养,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慕嚷,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡喝检,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了挠说。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡愿题,死狀恐怖损俭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抠忘,我是刑警寧澤撩炊,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站崎脉,受9級特大地震影響拧咳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜囚灼,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一骆膝、第九天 我趴在偏房一處隱蔽的房頂上張望祭衩。 院中可真熱鬧,春花似錦阅签、人聲如沸掐暮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽路克。三九已至,卻和暖如春养交,著一層夾襖步出監(jiān)牢的瞬間精算,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工碎连, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留灰羽,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓鱼辙,卻偏偏與公主長得像廉嚼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子倒戏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容