假設(shè)我們使用JAVA,element是WebElement的一個(gè)實(shí)例,這樣開(kāi)始:
element.getAttribute("row");
在內(nèi)部,元素有一個(gè)透明的ID,服務(wù)器用于識(shí)別是哪一個(gè)元素。為了便于討論,我們假設(shè)這個(gè)ID有一個(gè)值some_opaque_id,被加密成JAVA命令對(duì)象,使用MAP映射到一個(gè)參數(shù)ID和name,表示用于要查詢的屬性名的元素ID和name。
快速看一下正確的URL是:
/session/:sessionId/element/:id/attribute/:name
以冒號(hào)開(kāi)始的URL的任何部分假定是一個(gè)需要被替換的變量,我們已經(jīng)獲得ID和name,當(dāng)一個(gè)服務(wù)器可以同時(shí)處理多個(gè)會(huì)話(Firefox driver不能)時(shí),那么sessionId是另一種用于路由功能的不透明的句柄,這個(gè)URL因此像這樣擴(kuò)展:
http://localhost:7055/hub/session/XXX/element/some_opaque_id/attribute/row
順便說(shuō)一句,webdriver的遠(yuǎn)程線協(xié)議初是在與URL模板草案提出時(shí)同時(shí)開(kāi)發(fā)的,我們以明確URL及URL模板的方案允許在一個(gè)URL里進(jìn)行變量擴(kuò)展(派生)。遺憾的是,雖然URL模板同時(shí)提出,我們只意識(shí)到他們相對(duì)晚了,因此他們不會(huì)被用作設(shè)計(jì)線協(xié)議。
因?yàn)槲覀冋龍?zhí)行的方法是idempotent4,正確的HTTP方法是使用get,我們委托一個(gè)能處理HTTP(Apache的HTTP客戶端)來(lái)調(diào)用服務(wù)器的Java庫(kù)。
Firefox driver被實(shí)現(xiàn)成一個(gè)Firefox擴(kuò)展,它的基本設(shè)計(jì)如上圖所示。有些不同尋常的是,它有一個(gè)嵌入式HTTP服務(wù)器,雖然初我們使用我們自己創(chuàng)建的,在XPCOM上寫(xiě)的HTTP服務(wù)器并不是我們的核心競(jìng)爭(zhēng)力之一,所以機(jī)會(huì)出現(xiàn)時(shí),我們使用基本的由Mozilla自己寫(xiě)的HTTPD取代了它,HTTPD收到請(qǐng)求馬上傳遞給調(diào)度對(duì)象。
調(diào)度器接收請(qǐng)求并遍歷一個(gè)已知支持的URL列表,嘗試找到相匹配的請(qǐng)求,這種匹配完成了在客戶端上的變量插值,一旦精確匹配到,包括使用的動(dòng)作,JSON對(duì)象,意味著在構(gòu)造要執(zhí)行的命令。我們的案例中看起來(lái)像:
{
'name': 'getElementAttribute',
'sessionId': { 'value': 'XXX' },
'parameters': {
'id': 'some_opaque_key',
'name': 'rows'
}
然后將其作為一個(gè)JSON字符串傳遞到一個(gè)自定義的XPCOM組件中,我們叫它CommandProcessor。
var jsonResponseString = JSON.stringify(json);
var callback = function(jsonResponseString) {
var jsonResponse = JSON.parse(jsonResponseString);
if (jsonResponse.status != ErrorCode.SUCCESS) {
response.setStatus(Response.INTERNAL_ERROR);
}
response.setContentType('application/json');
response.setBody(jsonResponseString);
response.commit();
};
// Dispatch the command.
Components.classes['@googlecode.com/webdriver/command-processor;1'].
getService(Components.interfaces.nsICommandProcessor).
execute(jsonString, callback);
這里有大量的代碼,但是有兩個(gè)關(guān)鍵點(diǎn)。首先,我們把上面的對(duì)象轉(zhuǎn)換成JSON字符串,其次傳遞一個(gè)回調(diào)的執(zhí)行方法來(lái)發(fā)送HTTP響應(yīng)。