解釋器之惑
盡管通過(guò)這種方法可以使用JavaScript輕易的實(shí)現(xiàn)一個(gè)服務(wù)(不管運(yùn)行代碼的虛機(jī)實(shí)際上跑的是C程序還是其他什么程序),這種做法回避了一個(gè)問(wèn)題:你需要使用JavaScript寫(xiě)出一個(gè)服務(wù)器嗎?為了找到這個(gè)問(wèn)題的答案,我們來(lái)考慮一個(gè)非常典型的場(chǎng)景。
JSON的處理
這是一種非常典型的web應(yīng)用,前臺(tái)使用HTML和CSS,JavaScript用來(lái)作數(shù)據(jù)驗(yàn)證,并和后臺(tái)進(jìn)行數(shù)據(jù)交互。由于你處于web交互的最頂端,你使用Ajax提交數(shù)據(jù)到后臺(tái)并從后臺(tái)獲取數(shù)據(jù),而不是單單依靠表單提交來(lái)實(shí)現(xiàn)。如果你是這樣做的話(huà),那么你同樣會(huì)非常喜歡使用JSON的。JSON是如今最流行的傳輸數(shù)據(jù)的格式。
因此,這個(gè)Ajax也可以比作“把在線(xiàn)拍賣(mài)網(wǎng)站里的某些吉他的信息發(fā)給我”。這個(gè)請(qǐng)求通過(guò)網(wǎng)絡(luò)到達(dá)一個(gè)運(yùn)行PHP程序的服務(wù)器。PHP服務(wù)器不得不給JavaScript返回很多信息,而且這些信息必須以某種形式的數(shù)據(jù)包發(fā)給客戶(hù)端,而且這個(gè)數(shù)據(jù)包是可以被JavaScript解析的。因此數(shù)據(jù)可以打包成數(shù)組,然后轉(zhuǎn)換為JSON,就像這樣:
$itemGuitar = array( 'id' => 'itemGuitar', 'description' => 'Pete Townshend once played this guitar while his own axe ' . was in the shop having bits of drumkit removed from it.', 'price' => 5695.99, 'urls' => array('http://www.thewho.com', 'http://en.wikipedia.com/wiki/Pete_Townshend') );
$output = json_encode($itemGuitar); print($output);
回到客戶(hù)端,JavaScript得到這個(gè)返回的數(shù)據(jù)包,由于經(jīng)過(guò)轉(zhuǎn)換,數(shù)據(jù)編程了JSON格式。就像這樣:
{ "id": "itemGuitar", "description": "Pete Townshend once played this guitar...", "price": 5695.99, "urls": ["}
這種轉(zhuǎn)換是標(biāo)準(zhǔn)的,轉(zhuǎn)換前后也是相互等價(jià)的。接下來(lái),就可以將這個(gè)字符串轉(zhuǎn)換為JavaScript對(duì)象,可以調(diào)用eval(),就像這樣:
var itemDetails = eval('(' + jsonDataString + ')');
計(jì)算結(jié)果是一個(gè)普通的JavaScript對(duì)象,這個(gè)對(duì)象的屬性和JSON數(shù)組的數(shù)據(jù)結(jié)構(gòu)保持一致。當(dāng)然,由于jsonDataString通常是由服務(wù)器返回的,通常需要這樣來(lái)解析返回結(jié)果:
var itemDetails = eval('(' + request.responseText + ')');
這就是最最典型的JSON處理,但存在一個(gè)非常嚴(yán)重的問(wèn)題。
對(duì)實(shí)體代碼微妙的破壞性
(譯注:這個(gè)小標(biāo)題著實(shí)讓人費(fèi)解,作者這里拐彎抹角的解釋了Node的一個(gè)好處,就是前端和后端都采用同樣的語(yǔ)言JavaScript,在作JSON解析時(shí)是無(wú)障礙的,而當(dāng)前端使用JavaScript作JSON編碼,后臺(tái)用PHP作JSON解碼時(shí),多少會(huì)因?yàn)槎喾N語(yǔ)言的JSON解析的實(shí)現(xiàn)不同而帶來(lái)一些兼容性問(wèn)題)
首先,這類(lèi)代碼的一個(gè)主要問(wèn)題是,它對(duì)解釋器的依賴(lài)比較嚴(yán)重。在上個(gè)例子中,解釋器就是指內(nèi)置的JSON解析器或者實(shí)現(xiàn)解析JSON的代碼,這實(shí)際上依賴(lài)了兩樣?xùn)|西:和eval()解析響應(yīng)文本的操作一樣的基于Java的JSON解析器,以及基于PHP的JSON解析器。在PHP5.2.0中已經(jīng)包含了JSON解析器,但卻是以外部依賴(lài)的形式給出的,并不是內(nèi)置于PHP的內(nèi)核中。
但這并不是大肆宣揚(yáng)解釋器的種種。畢竟解釋器本身還存在很多問(wèn)題,比如將“I”解析成了“i”,數(shù)組中的元素1解釋成了2。當(dāng)然,在JSON工具正式發(fā)布之前會(huì)有大量的測(cè)試,以保證在各種復(fù)雜場(chǎng)景中都不會(huì)出現(xiàn)錯(cuò)誤,包括在客戶(hù)端的解析結(jié)果和在服務(wù)器端的解析結(jié)果完全一致。無(wú)論如何,這都需要大量的測(cè)試才行。
不管怎樣,JSON依然存在很多實(shí)際的問(wèn)題。
基于某種語(yǔ)言(基于JavaScript或者PHP)的JSON解析器選擇是一個(gè)很大的問(wèn)題。換句話(huà)說(shuō),問(wèn)題不是在于“翻譯”(translation)而在于“翻譯器”(translator)(譯注:作者的意思是說(shuō)JSON本身的規(guī)則沒(méi)有問(wèn)題,反倒是各種語(yǔ)言的JSON實(shí)現(xiàn)的質(zhì)量參差不齊,甚至有很多bug)。當(dāng)一個(gè)語(yǔ)言的版本比較穩(wěn)定時(shí),基于這門(mén)語(yǔ)言的JSON解析器的運(yùn)用和推廣會(huì)比較快。結(jié)果是,JSON解析器變的越來(lái)越強(qiáng)大,以至于可以解析任意復(fù)雜的數(shù)據(jù)結(jié)構(gòu),即便這么復(fù)雜的數(shù)據(jù)結(jié)構(gòu)根本不會(huì)實(shí)際用到。反之,每次迭代中(每次計(jì)算迭代的路徑和數(shù)據(jù)類(lèi)型的組合),也很有可能出現(xiàn)JSON解釋器無(wú)法解析的數(shù)據(jù)結(jié)構(gòu)(或者很深的JSON路徑)的情況。
下圖就是可選的JSON解釋器
這并不是說(shuō)JSON本身很糟糕,實(shí)際上,我們認(rèn)為JSON的流行正是得益于其在新領(lǐng)域中的應(yīng)用(譯注:作者的言外之意是,在新領(lǐng)域中的初次JSON實(shí)現(xiàn)往往伴隨很多問(wèn)題)。對(duì)于新的領(lǐng)域,我們不禁要問(wèn):“這個(gè)新東東支持JSON嗎?” 因此,JSON需要不斷進(jìn)化,需要不斷的測(cè)試,不斷的兼容新的平臺(tái)。而作為程序員的,可能需要重新組織你的數(shù)據(jù)結(jié)構(gòu),或者等待新的版本出現(xiàn)以滿(mǎn)足你的需求,或者干脆直接hack JSON。而這些正是我們所說(shuō)的編程資源的浪費(fèi)。
假設(shè)你可以自己動(dòng)手豐衣足食實(shí)現(xiàn)一個(gè)解釋器,即便這樣,你也沒(méi)有通過(guò)“抄近道”揀到便宜,而是用JavaScript重復(fù)造輪子而已。
而Node則規(guī)避了此類(lèi)問(wèn)題,剛剛你讀到的文字——關(guān)于內(nèi)嵌JSON的PHP5.2.0、關(guān)于將對(duì)象轉(zhuǎn)換為數(shù)組、關(guān)于采用新的結(jié)構(gòu)組織數(shù)據(jù)的方式、關(guān)于JSON中新特性的實(shí)現(xiàn)——這一切擾人的問(wèn)題在Node中都將不復(fù)存在,因?yàn)榍岸送ㄟ^(guò)JavaScript作JSON編碼,后臺(tái)使用JavaScript作JSON解碼,永遠(yuǎn)不會(huì)出問(wèn)題。
JavaScript中eval()的潛在隱患
正如我們不用將Node當(dāng)作一門(mén)新的語(yǔ)言來(lái)對(duì)待一樣,在Node中通過(guò)eval()來(lái)執(zhí)行一段代碼也和JavaScript中的eval()一樣(不被推薦)。眾所周知eval()是非常危險(xiǎn)的。eval()用以執(zhí)行一段文本表示的代碼邏輯,可以理解為在文本框中“直接敲入SQL代碼來(lái)執(zhí)行查詢(xún)”,這是不安全的,這實(shí)際上是惡意SQL注入。當(dāng)每次eval()執(zhí)行一段字符串的時(shí)候,(美國(guó))中西部的一只小狗都會(huì)瑟瑟發(fā)抖,東部海灘上的某位母親的腳趾會(huì)被刺傷并受到詛咒。eval()非常危險(xiǎn)。網(wǎng)上有很多關(guān)于此的資料,這里不再贅述?梢杂胓oogle查詢(xún)“eval JavaScript evil”或者“eval JavaScript injection”獲取更多信息。
當(dāng)然,如果沒(méi)有任何其他上下文的約束,在Node中也是允許使用eval()的,因此eval()的隱患在Node依然存在。畢竟Node的目的并不是完全解決eval()的問(wèn)題。Node被稱(chēng)之為基于事件的JavaScript或基于事件的I/O,這里所說(shuō)的“基于事件”是Node中非常重要的概念。但要徹底理解什么是基于事件,以及為什么基于事件能讓你規(guī)避eval()的危險(xiǎn),則需要理解JSON在應(yīng)用之中是如何工作的,此外還要搞清楚適應(yīng)于web應(yīng)用典型架構(gòu)的特有數(shù)據(jù)結(jié)構(gòu)。
出處:Taobao.com UED Team
責(zé)任編輯:bluehearts
上一頁(yè) 什么是Node? [6] 下一頁(yè) 什么是Node? [8]
◎進(jìn)入論壇網(wǎng)頁(yè)制作、WEB標(biāo)準(zhǔn)化版塊參加討論,我還想發(fā)表評(píng)論。
|