ASIHTTPRequest源码简单分析
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
1.前言
? ? ?ASIHttprequest 是基于CFNetwork的,由于CFNetwork是比較底層的http庫,功能比較少,因此,在ASIHttprequest中實現(xiàn)了http協(xié)議中比較多的功能,包括代理、gzip、認(rèn)證、緩存等等。目前,雖然ASIHTTPRequest已經(jīng)不如前兩年那么流行,但是分析一下其代碼,對掌握CFNetwork庫和HTTP協(xié)議還是有好處的,本文將簡單分析一下ASIHTTPRequest中幾個主要函數(shù)的流程。
?
2.處理HTTP Request的主要函數(shù)
ASIHTTPRequest::main流程如下(只列舉了主要工作):
{
? ? ?(1)若允許后臺運(yùn)行,則調(diào)用beginBackgroundTaskWithExpirationHandler允許程序后臺運(yùn)行十分鐘
? ? ?(2) 調(diào)用buildPostBody函數(shù)構(gòu)造post的body部分,該函數(shù)有兩個,一個是基類中的,主要負(fù)責(zé)壓縮body數(shù)據(jù),另一個是派生類ASIFormDataRequest中,分別針對post表單和post文件的方式,分別設(shè)置content-type為application/x-www-form-urlencoded和multipart/form-data。
? ? ?(3)根據(jù)url和請求的方法來創(chuàng)建CFHTTPMessageRef對象。
? ? ?(4)調(diào)用buildRequestHeaders函數(shù)來構(gòu)造header部分,這里只是簡單的將各個header字段放到一個NSDictionary變量中。
? ? ?(5)如果設(shè)置了緩存,并且允許從緩存取數(shù)據(jù),則從緩存中讀取數(shù)據(jù),然后返回。
? ? ?(6)調(diào)用applyAuthorizationHeader向header字典中添加HTTP認(rèn)證相關(guān)的字段。
? ? ?(7)調(diào)用CFHTTPMessageSetHeaderFieldValue來將header數(shù)據(jù)添加到CFHTTPMessageRef對象中。
? ? ?(8)調(diào)用configureProxies來配置代理。
? ? ?(9)調(diào)用startRequest來發(fā)送請求。
}
?
ASIHTTPRequest::startRequest
{ ??
? ? ? (1)向主線程發(fā)送requestStarted消息
? ? ? (2)如果存在body,且需要post本地文件,則將本地文件讀到postBodyReadStream對象中。然后調(diào)用CFReadStreamCreateForStreamedHTTPRequest函數(shù),傳入之前創(chuàng)建的CFHTTPMessageRef對象和postBodyReadStream對象,來創(chuàng)建一個用來讀取response 的CFReadStream對象。
? ? ? ? ? ? ?如果是post數(shù)據(jù),則先根據(jù)shouldCompressRequestBody的值來判斷是否要壓縮,然后根據(jù)postBody的數(shù)據(jù)來創(chuàng)建一個NSInputStream對象,并賦給postBodyReadStream對象,然后調(diào)用CFReadStreamCreateForStreamedHTTPRequest,傳入之前的header和stream對象,來創(chuàng)建NSReadStream對象。
? ? ? ? ? ? ?如果不存在body,則直接通過CFReadStreamCreateForHTTPRequest函數(shù)來創(chuàng)建NSReadStream對象。
? ? (3)針對https的情況,調(diào)用CFReadStreamSetProperty進(jìn)行設(shè)置
? ? (4)如果請求中設(shè)置了代理,則調(diào)用CFReadStreamSetProperty對stream進(jìn)行代理相關(guān)的設(shè)置
? ? ?(5)處理http持久連接相關(guān)的設(shè)置
? ? (6)調(diào)用scheduleInRunLoop,將readStream對象放入runloop中
? ? (7)調(diào)用CFReadStreamSetClient函數(shù)來將readStream關(guān)聯(lián)到一個回調(diào)函數(shù)ReadStreamClientCallBack中,并使用CFReadStreamOpen打開readStream對象
? (8)調(diào)用進(jìn)度通知相關(guān)的函數(shù)
? ?(9)創(chuàng)建一個計時器,用來調(diào)用updateStatus函數(shù)來更新進(jìn)度,并將計時器放入當(dāng)前runloop。
}
?
3.處理HTTP Response的主要函數(shù)?
ASIHTTPRequest::handleNetworkEvent (該函數(shù)用來處理回調(diào)事件)
{
? ? (1)當(dāng)收到kCFStreamEventHasBytesAvailable 事件時 ,調(diào)用handleBytesAvailable(此時表示下層已經(jīng)讀到了response里的數(shù)據(jù),這數(shù)據(jù)可能包含全部的header也可能header尚未讀完)
? ? (2)kCFStreamEventEndEncountered,調(diào)用handleStreamComplete,此時表示全部的數(shù)據(jù)包括header和body都已經(jīng)讀完,而且對應(yīng)chunked數(shù)據(jù),底層也已經(jīng)將其合并完。
? ? (3)kCFStreamEventErrorOccurred事件,調(diào)用handleStreamError處理錯誤
}
?
ASIHTTPRequest::handleBytesAvailable
{
? ? (1)如果responseHeader對象尚未賦值,則調(diào)用readResponseHeaders讀取header
? ? (2)申請一塊buffer,讀取readStream對象里面的數(shù)據(jù),此時如果能讀到數(shù)據(jù),則表示header已經(jīng)讀完了,當(dāng)前讀到的是body里面數(shù)據(jù)(因為header不是用read方法讀的),如果讀不到數(shù)據(jù),則表示還沒有收到body,則返回。
? ? (3)讀取到數(shù)據(jù)之后,如果header里面顯示數(shù)據(jù)是壓縮過的,則進(jìn)行解壓縮
? ? (4)解壓出數(shù)據(jù)之后有三種處理方式:
? ? ? ? ? ? ?如果用戶設(shè)置了didReceiveDataSelector或者dataReceivedBlock,這就表示用戶希望自己處理每次得到的data,則向主線程發(fā)送passOnReceivedData消息。
? ? ? ? ? ? ?如果用戶在request中設(shè)置了下載路徑,則將數(shù)據(jù)寫到文件中
? ? ? ? ? ? ?如果以上都不滿足,則將數(shù)據(jù)append到rawResponseData中。
}
ASIHTTPRequest::readResponseHeaders
{
? ?(1)使用CFReadStreamCopyProperty從readStream對象中讀取header,創(chuàng)建一個CFHTTPMessageRef對象,并且使用CFHTTPMessageIsHeaderComplete檢查該對象,判斷header是否已經(jīng)讀完,若沒有讀完,則銷毀該對象并返回
? ?(2)?使用CFHTTPMessageCopyAllHeaderFields從CFHTTPMessageRef讀出header到一個dictionary中
? ? (3)如果有緩存,且允許讀取緩存,則從緩存中讀取header并返回。
? ?(4)根據(jù)header中的狀態(tài)碼來判斷是否需要進(jìn)行http認(rèn)證,如果需要則處理認(rèn)證相關(guān)的工作
? ?(5) 從header中content-type,用于對body進(jìn)行解碼,如沒有該字段,則使用默認(rèn)的解碼方式對content進(jìn)行解碼
? ?(6)處理cookie相關(guān)的工作
? ?(7)如果不需要重定向,則從header中讀取content-length,然后根據(jù)length做相關(guān)處理
? ?(8)處理keepalive相關(guān)的工作
? ?(9)最后向主線程發(fā)送requestReceivedResponseHeaders通知
}
ASIHTTPRequest::handleStreamComplete
{
? ? ?該函數(shù)做的事情比較簡單,主要就是設(shè)置各種下載結(jié)束的標(biāo)志、設(shè)置讀取到的文件大小并發(fā)送通知消息、移動下載的臨時文件、保存cache等等。
}
轉(zhuǎn)載于:https://my.oschina.net/kings0527/blog/591588
總結(jié)
以上是生活随笔為你收集整理的ASIHTTPRequest源码简单分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        