仲曉,廖建新
(1 北京郵電大學(xué)網(wǎng)絡(luò)與交換技術(shù)國家重點實驗室,北京 100876;2 東信北郵信息技術(shù)有限公司,北京 100191)
隨著互聯(lián)網(wǎng)的快速發(fā)展和Web應(yīng)用的迅速增多,越來越多的Web服務(wù)被發(fā)布到互聯(lián)網(wǎng)上。網(wǎng)站信息的海量增長,給人們的生活和工作帶來了極大的便利,但網(wǎng)頁的代碼量及網(wǎng)頁中圖像、視頻、動態(tài)代碼等元素的增加,導(dǎo)致了網(wǎng)站加載時間變長,網(wǎng)頁的瀏覽速度變慢,影響了用戶的上網(wǎng)體驗,從而降低了網(wǎng)站的訪問量。
對于網(wǎng)站的開發(fā)商而言,提升網(wǎng)站的加載速度是非常有必要的,這不僅有利于優(yōu)化搜索排名和降低運營成本,同時也能極大的提高用戶的體驗度。
瀏覽器加載一個網(wǎng)站,可以分為以下幾個步驟:域名解析、TCP連接、上傳請求、等待響應(yīng)、HTML文檔下載、HTML文檔解析、頁面資源下載。本文基于Webkit開源瀏覽器內(nèi)核來模擬瀏覽器加載網(wǎng)站的過程,在分析Webkit的基礎(chǔ)上,重點討論Webkit加載頁面的過程及信息的獲取。
Webkit是開源的瀏覽器引擎,其內(nèi)核高效穩(wěn)定、兼容性好,源代碼清晰,便于維護,Apple的Safari、Google的Chrome都是基于Webkit內(nèi)核開發(fā)的,并且iPhone和Android手機系統(tǒng)中的瀏覽器也是使用Webkit作為瀏覽器內(nèi)核。
Webkit的層次框架如圖 1所示,分為3個層次:Webkit、WebCore和 JavaScriptCore,Webkit層主要是與操作系統(tǒng)的交互;WebCore層是Webkit的核心,包括頁面渲染、布局、繪制、DOM綁定等功能;JavaScriptCore層包括JavaScript Engine和JavaScript腳本的執(zhí)行。
圖1 Webkit層次框架
Webkit瀏覽器內(nèi)核的功能主要包括:加載、文檔解析、渲染、Style解析、布局、Script執(zhí)行等。
加載是獲取資源數(shù)據(jù),包括頁面加載和頁面所包含資源的加載。頁面加載主要由FrameLoader完成,資源的加載是由DocLoader和Cache完成,頁面和資源都是用CachedResource表示,可以分為RawResource、Image、Font、Script、SVGDocument等幾種資源類型。
文檔解析是根據(jù)HTML或XML文檔結(jié)構(gòu)構(gòu)建DOM樹,DOM樹用來描述頁面的結(jié)構(gòu),節(jié)點包括Element Node、Attribute Node、CSS Style Sheets。
渲染階段是創(chuàng)建Render樹,在文檔解析時,每增加一個DOM節(jié)點,都會調(diào)用Node類的attach方法,計算該節(jié)點style屬性中display值,如果非“none”,則創(chuàng)建該節(jié)點的Render對象,并添加到Render樹中。Render樹中包含所有需要在窗口中繪制的信息,并且Render樹屬于DOM樹。
Style解析是構(gòu)建RenderStyle樹,Node::attach方法中將計算結(jié)點的Style信息,添加到樹中,RenderStyle樹中包含CSS Style信息,并且RenderObject共享Style。
在為節(jié)點的Render對象添加到Render樹時,這些對象中沒有位置和大小信息,將通過執(zhí)行Render::layout方法,實現(xiàn)對節(jié)點的布局操作。
JavaScript引擎通過掃描JavaScript源碼,構(gòu)建語法樹,然后通過函數(shù)調(diào)用觸發(fā)語法樹求值。在JavaScript執(zhí)行過程中,通過修改DOM樹來修改文檔的結(jié)構(gòu)和結(jié)點的屬性,并且同時反映到Render樹中。
Webkit通過WebCore和JavaScriptCore處理下載的內(nèi)容,并進行文本、圖片等元素的顯示及JavaScript腳本的執(zhí)行。一個HTTP請求在Webkit中處理的流程如下:
(1)首先進行主頁面加載,Webkit將主頁面的加載請求經(jīng)過Webkit引擎的內(nèi)部封裝成CFURLRequestRef,交由Webkit引擎和底層網(wǎng)絡(luò)庫的接口ResourceHandle,進行資源的下載過程;
(2)Win32平 臺 使 用 的 是CFNetwork網(wǎng) 絡(luò)庫,通過調(diào)用網(wǎng)絡(luò)庫的異步函數(shù)實現(xiàn)資源的下載,ResourceHandle是Webkit引擎和網(wǎng)絡(luò)庫的接口,通過調(diào)用ResourceHandle::start()來發(fā)起網(wǎng)絡(luò)請求,當(dāng)網(wǎng)絡(luò)事件到達時,將調(diào)用注冊的回調(diào)函數(shù):
willSendRequest(CFURLConnectionRef,CFURLRequestRef, CFURLResponseRef, const void*):在發(fā)送請求之前調(diào)用,對發(fā)送的請求進行預(yù)處理;
didReceiveResponse(CFURLConnectionRef,CFURLResponseRef, const void*):收到來自服務(wù)器返回的響應(yīng)時調(diào)用,主要處理接收到的HTTP響應(yīng)頭,如,對狀態(tài)碼為“304 Not Modified”資源的請求,直接從Cache中獲得資源信息;
ata(CFURLConnectionRef,CFDataRef, CFIndex, const void*):收到服務(wù)器發(fā)送的數(shù)據(jù)時調(diào)用,對于主頁面資源,將對接收到的HTML文本進行解析,構(gòu)建DOM樹、Render樹等,并且在解析過程中伴隨著對圖片、腳本文件等其他資源的加載及解析得到的腳本片段的執(zhí)行過程;
didFinishLoading(CFURLConnectionRef, const void*):服務(wù)器對請求的響應(yīng)結(jié)束時調(diào)用,此時客戶端已接收到服務(wù)器返回的所有數(shù)據(jù)。
(3)在HTML解析過程中,DOM將HTML文本解析成DOM樹,如果請求的頁面中包含圖片、腳本等資源時,將同樣通過ResourceHandle::start()發(fā)送對應(yīng)的網(wǎng)絡(luò)請求進行資源的下載;
(4)如果接收到JavaScript腳本或者解析到嵌入在HTML文件中的JavaScript腳本,將交由JavaScriptCore執(zhí)行,并且在執(zhí)行過程中對DOM樹進行完善;
(5)最后通過布局管理器分析HTML中可視元素的高度、寬度和位置等信息,進行布局排版,具有CSS樣式的元素通過CSS解析器進行解析,最后通過Rendering顯示給用戶。
基于Webkit對HTTP請求的處理過程,網(wǎng)站加載過程監(jiān)控系統(tǒng)主要由兩部分組成:加載過程監(jiān)控和數(shù)據(jù)存儲。加載過程的監(jiān)控是模擬瀏覽器請求HTTP頁面,記錄頁面加載的過程各個階段所用的時間,構(gòu)成一個頁面的加載過程記錄;數(shù)據(jù)存儲將加載過程監(jiān)控產(chǎn)生的加載過程記錄組織并存放到數(shù)據(jù)庫中。
網(wǎng)站加載過程的監(jiān)控主要需要兩個數(shù)據(jù)表,一個是記錄需要進行監(jiān)控的網(wǎng)站信息表monitor_item_info,另一個是存儲監(jiān)控所得到的結(jié)果表monitor_result。監(jiān)控信息表和監(jiān)控結(jié)果記錄表的結(jié)構(gòu)如圖 2所示。
圖2 monitor_item_info和monitor_result 結(jié)構(gòu)圖
(1) 監(jiān)控信息表monitor_item_info:
item_id記錄項目ID,是表的主鍵;
item_info記錄監(jiān)控項目的描述信息,允許為空;
url記錄監(jiān)控對象的URL地址;
gap記錄監(jiān)控時間間隔,表示項目監(jiān)控的周期,單位是min,默認(rèn)值5min。
(2) 監(jiān)控結(jié)果記錄表monitor_result:
operation_id記錄監(jiān)控項目一次監(jiān)控操作的ID;
resource_no記錄監(jiān)控結(jié)果對應(yīng)的資源在本次監(jiān)控操作中的內(nèi)部序號,(operation_id,resource_no)作為主鍵;
item_id記錄監(jiān)控結(jié)果屬于的監(jiān)控項目ID,對應(yīng)monitor_item_info中的item_id;
url記錄資源對應(yīng)的url地址;
start_time記錄本次監(jiān)控操作開始時間戳;
stop_time記錄本次監(jiān)控操作結(jié)束時間戳;
type記錄監(jiān)控資源的類型,資源的類型分為:main、image、script、cssstyle、link、font、other;
send_request_time記錄向服務(wù)器發(fā)送資源請求的時間戳;
receive_response_time記錄從服務(wù)器接收到響應(yīng)的時間戳;
finish_download_time記錄從服務(wù)器下載到所有資源的時間戳;
如HTML在下載過程需要交由解析器進行解析,JavaScript腳本在下載過程需交由JavaScript Engine執(zhí)行,process_start_time記錄處理開始時間,process_end_time記錄處理結(jié)束時間;
在資源下載過程中可能會需要經(jīng)過多次服務(wù)器下載操作,data_download_times記錄資源數(shù)據(jù)下載次數(shù);
data_size記錄資源數(shù)據(jù)總字節(jié)數(shù);
error_id記錄當(dāng)前監(jiān)控結(jié)果的錯誤類型,0表示無錯誤。
圖3 主要類圖
代碼中定義類MonitorItemInfo用來表示一個資源的信息,MonitorResult用來表示一個資源加載結(jié)果的信息,類中各個字段分別與表monitor_item_info和表monitor_result的相應(yīng)字段對應(yīng),并且定義類MonitorResultStore用來將監(jiān)控結(jié)果存放到數(shù)據(jù)庫中,如圖 3所示。
其中方法MonitorResultStore::addMonitorResult(MonitorResult*)將監(jiān)控結(jié)果保存到m_monitorResult List中,然后線程m_monitorResultStoreThread定時將結(jié)果存儲到數(shù)據(jù)庫中。
根據(jù)2.2節(jié)中關(guān)于HTTP請求流程的分析,在HTTP請求的過程中記錄加載過程所得到的監(jiān)控結(jié)果信息。具體過程如下:方法CachedResource Lo ader::requestResource(CachedResource::Ty pe, CachedResourceRequest&)中 根 據(jù)Cached Resource::Type得到請求資源的類型,根據(jù)CachedResourceRequest得到請求資源的url;方法willSendRequest在發(fā)送請求時調(diào)用,并記錄了變量m_sendRequestTime;方法didReceiveResponse在接收到服務(wù)器響應(yīng)時調(diào)用,記錄了變量m_receiveResponse Time,并且根據(jù)響應(yīng)信息得到HTTP響應(yīng)的狀態(tài)碼,并判斷是否發(fā)生錯誤;方法didReceiveData中累計從服務(wù)器下載的數(shù)據(jù)大小m_dataSize和調(diào)用次數(shù)m_downloadDataTimes;方法didFinishLoading在數(shù)據(jù)全部下載完畢時調(diào)用,記錄m_finishDownload Time;HTML文件和Java Script腳本的執(zhí)行,在解析完畢或者腳本執(zhí)行完畢時記錄m_processTime,其他資源的m_processTime設(shè)為0。每次資源加載完畢之后,將得到的結(jié)果MonitorResult通 過MonitorResultStore保存到數(shù)據(jù)庫中。
本文對Webkit瀏覽器內(nèi)核的頁面加載和HTTP請求處理流程等技術(shù)進行了研究和分析,設(shè)計并實現(xiàn)了基于Webkit瀏覽器內(nèi)核的網(wǎng)站加載過程的監(jiān)控系統(tǒng),能夠通過模擬瀏覽器來監(jiān)控網(wǎng)站的加載過程。根據(jù)監(jiān)控系統(tǒng)得到的結(jié)果進行分析,可得到網(wǎng)站在加載過程中的瓶頸,有利于改善網(wǎng)站的性能。本系統(tǒng)目前只是模擬了基于Webkit內(nèi)核的瀏覽器加載頁面的過程,其他瀏覽器內(nèi)核的加載過程有待研究。
[1] Webkit. The Webkit Open Project[EB/OL].http://www.Webkit.org/.
[2] 趙經(jīng)緯, 周余, 王自強等. 基于Webkit的嵌入式瀏覽器的研究與實現(xiàn)[J]. 電子測量技術(shù), 2009,32(3):135-138.
[3] 倪建新. 基于Webkit的嵌入式瀏覽器關(guān)鍵技術(shù)研究與實現(xiàn)[J].智能計算機與應(yīng)用, 2011,01(6):47-48,51.
[4] 謝立丹, 陳榕. 基于Elastos的Webkit引擎的研究與移植[J]. 計算機技術(shù)與發(fā)展,2011,21(1):12-15.
[5] 張光輝, 劉清梅, 李武等. 基于實時監(jiān)控的網(wǎng)站反篡改系統(tǒng)設(shè)計[J]. 價值工程,2012,31(4):133-134.