ASIHttprequest 是基於CFNetwork的,因爲CFNetwork是比較底層的http庫,功能比較少,所以,在ASIHttprequest中實現了http協議中比較多的功能,包括代理、gzip、認證、緩存等等。目前,雖然ASIHTTPRequest已經不如前兩年那麼流行,可是分析一下其代碼,對掌握CFNetwork庫和HTTP協議仍是有好處的,本文將簡單分析一下ASIHTTPRequest中幾個主要函數的流程。緩存
{cookie
(1)若容許後臺運行,則調用beginBackgroundTaskWithExpirationHandler容許程序後臺運行十分鐘併發
(2) 調用buildPostBody函數構造post的body部分,該函數有兩個,一個是基類中的,主要負責壓縮body數據,另外一個是派生類ASIFormDataRequest中,分別針對post表單和post文件的方式,分別設置content-type爲application/x-www-form-urlencoded和multipart/form-data。app
(3)根據url和請求的方法來建立CFHTTPMessageRef對象。函數
(4)調用buildRequestHeaders函數來構造header部分,這裏只是簡單的將各個header字段放到一個NSDictionary變量中。oop
(5)若是設置了緩存,而且容許從緩存取數據,則從緩存中讀取數據,而後返回。post
(6)調用applyAuthorizationHeader向header字典中添加HTTP認證相關的字段。ui
(7)調用CFHTTPMessageSetHeaderFieldValue來將header數據添加到CFHTTPMessageRef對象中。url
(8)調用configureProxies來配置代理。spa
(9)調用startRequest來發送請求。
}
{
(1)向主線程發送requestStarted消息
(2)若是存在body,且須要post本地文件,則將本地文件讀到postBodyReadStream對象中。而後調用CFReadStreamCreateForStreamedHTTPRequest函數,傳入以前建立的CFHTTPMessageRef對象和postBodyReadStream對象,來建立一個用來讀取response 的CFReadStream對象。
若是是post數據,則先根據shouldCompressRequestBody的值來判斷是否要壓縮,而後根據postBody的數據來建立一個NSInputStream對象,並賦給postBodyReadStream對象,而後調用CFReadStreamCreateForStreamedHTTPRequest,傳入以前的header和stream對象,來建立NSReadStream對象。
若是不存在body,則直接經過CFReadStreamCreateForHTTPRequest函數來建立NSReadStream對象。
(3)針對https的狀況,調用CFReadStreamSetProperty進行設置
(4)若是請求中設置了代理,則調用CFReadStreamSetProperty對stream進行代理相關的設置
(5)處理http持久鏈接相關的設置
(6)調用scheduleInRunLoop,將readStream對象放入runloop中
(7)調用CFReadStreamSetClient函數來將readStream關聯到一個回調函數ReadStreamClientCallBack中,並使用CFReadStreamOpen打開readStream對象
(8)調用進度通知相關的函數
(9)建立一個計時器,用來調用updateStatus函數來更新進度,並將計時器放入當前runloop。
}
{
(1)當收到kCFStreamEventHasBytesAvailable 事件時 ,調用handleBytesAvailable(此時表示下層已經讀到了response裏的數據,這數據可能包含所有的header也可能header還沒有讀完)
(2)kCFStreamEventEndEncountered,調用handleStreamComplete,此時表示所有的數據包括header和body都已經讀完,並且對應chunked數據,底層也已經將其合併完。
(3)kCFStreamEventErrorOccurred事件,調用handleStreamError處理錯誤
}
{
(1)若是responseHeader對象還沒有賦值,則調用readResponseHeaders讀取header
(2)申請一塊buffer,讀取readStream對象裏面的數據,此時若是能讀到數據,則表示header已經讀完了,當前讀到的是body裏面數據(由於header不是用read方法讀的),若是讀不到數據,則表示尚未收到body,則返回。
(3)讀取到數據以後,若是header裏面顯示數據是壓縮過的,則進行解壓縮
(4)解壓出數據以後有三種處理方式:
若是用戶設置了didReceiveDataSelector或者dataReceivedBlock,這就表示用戶但願本身處理每次獲得的data,則向主線程發送passOnReceivedData消息。
若是用戶在request中設置了下載路徑,則將數據寫到文件中
若是以上都不知足,則將數據append到rawResponseData中。
}
{
(1)使用CFReadStreamCopyProperty從readStream對象中讀取header,建立一個CFHTTPMessageRef對象,而且使用CFHTTPMessageIsHeaderComplete檢查該對象,判斷header是否已經讀完,若沒有讀完,則銷燬該對象並返回
(2) 使用CFHTTPMessageCopyAllHeaderFields從CFHTTPMessageRef讀出header到一個dictionary中
(3)若是有緩存,且容許讀取緩存,則從緩存中讀取header並返回。
(4)根據header中的狀態碼來判斷是否須要進行http認證,若是須要則處理認證相關的工做
(5) 從header中content-type,用於對body進行解碼,如沒有該字段,則使用默認的解碼方式對content進行解碼
(6)處理cookie相關的工做
(7)若是不須要重定向,則從header中讀取content-length,而後根據length作相關處理
(8)處理keepalive相關的工做
(9)最後向主線程發送requestReceivedResponseHeaders通知
}
{
該函數作的事情比較簡單,主要就是設置各類下載結束的標誌、設置讀取到的文件大小併發送通知消息、移動下載的臨時文件、保存cache等等。
}