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