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