ASIHTTPRequest源碼簡單分析

1.前言

     ASIHttprequest 是基於CFNetwork的,因爲CFNetwork是比較底層的http庫,功能比較少,所以,在ASIHttprequest中實現了http協議中比較多的功能,包括代理、gzip、認證、緩存等等。目前,雖然ASIHTTPRequest已經不如前兩年那麼流行,可是分析一下其代碼,對掌握CFNetwork庫和HTTP協議仍是有好處的,本文將簡單分析一下ASIHTTPRequest中幾個主要函數的流程。緩存

 

2.處理HTTP Request的主要函數

ASIHTTPRequest::main流程以下(只列舉了主要工做):

{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來發送請求。

}

 

ASIHTTPRequest::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。

}

 

3.處理HTTP Response的主要函數 

ASIHTTPRequest::handleNetworkEvent (該函數用來處理回調事件)

{

    (1)當收到kCFStreamEventHasBytesAvailable 事件時 ,調用handleBytesAvailable(此時表示下層已經讀到了response裏的數據,這數據可能包含所有的header也可能header還沒有讀完)

    (2)kCFStreamEventEndEncountered,調用handleStreamComplete,此時表示所有的數據包括header和body都已經讀完,並且對應chunked數據,底層也已經將其合併完。

    (3)kCFStreamEventErrorOccurred事件,調用handleStreamError處理錯誤

}

 

ASIHTTPRequest::handleBytesAvailable

{

    (1)若是responseHeader對象還沒有賦值,則調用readResponseHeaders讀取header

    (2)申請一塊buffer,讀取readStream對象裏面的數據,此時若是能讀到數據,則表示header已經讀完了,當前讀到的是body裏面數據(由於header不是用read方法讀的),若是讀不到數據,則表示尚未收到body,則返回。

    (3)讀取到數據以後,若是header裏面顯示數據是壓縮過的,則進行解壓縮

    (4)解壓出數據以後有三種處理方式:

             若是用戶設置了didReceiveDataSelector或者dataReceivedBlock,這就表示用戶但願本身處理每次獲得的data,則向主線程發送passOnReceivedData消息。

             若是用戶在request中設置了下載路徑,則將數據寫到文件中

             若是以上都不知足,則將數據append到rawResponseData中。

}

ASIHTTPRequest::readResponseHeaders

{

   (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通知

}

ASIHTTPRequest::handleStreamComplete

{

     該函數作的事情比較簡單,主要就是設置各類下載結束的標誌、設置讀取到的文件大小併發送通知消息、移動下載的臨時文件、保存cache等等。

}

相關文章
相關標籤/搜索