Web最初采用的“服務器-浏覽器”方案可提供交互式內容,但這種交互能力完全由服務器提供,為服務器和因特網帶來了不小的負擔。服務器一般為客戶浏覽器產生靜態網頁,由後者簡單地解釋並顯示出來。基本HTML語言提供了簡單的數據收集機制:文字輸入框、復選框、單選鈕、列表以及下拉列表等,另外還有一個按鈕,只能由程序規定重新設置表單中的數據,以便回傳給服務器。用戶提交的信息通過所有Web服務器均能支持的“通用網關接口”(CGI)回傳到服務器。包含在提交數據中的文字指示CGI該如何操作。最常見的行動是運行位於服務器的一個程序。那個程序一般保存在一個名為“cgi-bin”的目錄中(按下Web頁內的一個按鈕時,請注意一下浏覽器頂部的地址窗,經常都能發現“cgi-bin”的字樣)。大多數語言都可用來編制這些程序,但其中最常見的是Perl。這是由於Perl是專為文字的處理及解釋而設計的,所以能在任何服務器上安裝和使用,無論采用的處理器或操作系統是什麼。
注:本節內容改編自某位作者的一篇文章。那篇文章最早出現在位於www.mainspring.com的Mainspring上。本節的采用已征得了對方的同意。
今天的許多Web站點都嚴格地建立在CGI的基礎上,事實上幾乎所有事情都可用CGI做到。唯一的問題就是響應時間。CGI程序的響應取決於需要傳送多少數據,以及服務器和因特網兩方面的負擔有多重(而且CGI程序的啟動比較慢)。Web的早期設計者並未預料到當初綽綽有余的帶寬很快就變得不夠用,這正是大量應用充斥網上造成的結果。例如,此時任何形式的動態圖形顯示都幾乎不能連貫地顯示,因為此時必須創建一個GIF文件,再將圖形的每種變化從服務器傳遞給客戶。而且大家應該對輸入表單上的數據校驗有著深刻的體會。原來的方法是我們按下網頁上的提交按鈕(Submit);數據回傳給服務器;服務器啟動一個CGI程序,檢查用戶輸入是否有錯;格式化一個HTML頁,通知可能遇到的錯誤,並將這個頁回傳給我們;隨後必須回到原先那個表單頁,再輸入一遍。這種方法不僅速度非常慢,也顯得非常繁瑣。
解決的辦法就是客戶端的程序設計。運行Web浏覽器的大多數機器都擁有足夠強的能力,可進行其他大量工作。與此同時,原始的靜態HTML方法仍然可以采用,它會一直等到服務器送回下一個頁。客戶端編程意味著Web浏覽器可獲得更充分的利用,並可有效改善Web服務器的交互(互動)能力。
對客戶端編程的討論與常規編程問題的討論並沒有太大的區別。采用的參數肯定是相同的,只是運行的平台不同:Web浏覽器就象一個有限的操作系統。無論如何,我們仍然需要編程,仍然會在客戶端編程中遇到大量問題,同時也有很多解決的方案。在本節剩下的部分裡,我們將對這些問題進行一番概括,並介紹在客戶端編程中采取的對策。
1. 插件
朝客戶端編程邁進的時候,最重要的一個問題就是插件的設計。利用插件,程序員可以方便地為浏覽器添加新功能,用戶只需下載一些代碼,把它們“插入”浏覽器的適當位置即可。這些代碼的作用是告訴浏覽器“從現在開始,你可以進行這些新活動了”(僅需下載這些插入一次)。有些快速和功能強大的行為是通過插件添加到浏覽器的。但插件的編寫並不是一件簡單的任務。在我們構建一個特定的站點時,可能並不希望涉及這方面的工作。對客戶端程序設計來說,插件的價值在於它允許專業程序員設計出一種新的語言,並將那種語言添加到浏覽器,同時不必經過浏覽器原創者的許可。由此可以看出,插件實際是浏覽器的一個“後門”,允許創建新的客戶端程序設計語言(盡管並非所有語言都是作為插件實現的)。
2. 腳本編制語言
插件造成了腳本編制語言的爆炸性增長。通過這種腳本語言,可將用於自己客戶端程序的源碼直接插入HTML頁,而對那種語言進行解釋的插件會在HTML頁顯示的時候自動激活。腳本語言一般都傾向於盡量簡化,易於理解。而且由於它們是從屬於HTML頁的一些簡單正文,所以只需向服務器發出對那個頁的一次請求,即可非常快地載入。缺點是我們的代碼全部暴露在人們面前。另一方面,由於通常不用腳本編制語言做過份復雜的事情,所以這個問題暫且可以放在一邊。
腳本語言真正面向的是特定類型問題的解決,其中主要涉及如何創建更豐富、更具有互動能力的圖形用戶界面(GUI)。然而,腳本語言也許能解決客戶端編程中80%的問題。你碰到的問題可能完全就在那80%裡面。而且由於腳本編制語言的宗旨是盡可能地簡化與快速,所以在考慮其他更復雜的方案之前(如Java及ActiveX),首先應想一下腳本語言是否可行。
目前討論得最多的腳本編制語言包括JavaScript(它與Java沒有任何關系;之所以叫那個名字,完全是一種市場策略)、VBScript(同Visual Basic很相似)以及Tcl/Tk(來源於流行的跨平台GUI構造語言)。當然還有其他許多語言,也有許多正在開發中。
JavaScript也許是目常用的,它得到的支持也最全面。無論NetscapeNavigator,Microsoft Internet Explorer,還是Opera,目前都提供了對JavaScript的支持。除此以外,市面上講述JavaScript的書籍也要比講述其他語言的書多得多。有些工具還能利用JavaScript自動產生網頁。當然,如果你已經有Visual Basic或者Tcl/Tk的深厚功底,當然用它們要簡單得多,起碼可以避免學習新語言的煩惱(解決Web方面的問題就已經夠讓人頭痛了)。
3. Java
如果說一種腳本編制語言能解決80%的客戶端程序設計問題,那麼剩下的20%又該怎麼辦呢?它們屬於一些高難度的問題嗎?目前最流行的方案就是Java。它不僅是一種功能強大、高度安全、可以跨平台使用以及國際通用的程序設計語言,也是一種具有旺盛生命力的語言。對Java的擴展是不斷進行的,提供的語言特性和庫能夠很好地解決傳統語言不能解決的問題,比如多線程操作、數據庫訪問、連網程序設計以及分布式計算等等。Java通過“程序片”(Applet)巧妙地解決了客戶端編程的問題。
程序片(或“小應用程序”)是一種非常小的程序,只能在Web浏覽器中運行。作為Web頁的一部分,程序片代碼會自動下載回來(這和網頁中的圖片差不多)。激活程序片後,它會執行一個程序。程序片的一個優點體現在:通過程序片,一旦用戶需要客戶軟件,軟件就可從服務器自動下載回來。它們能自動取得客戶軟件的最新版本,不會出錯,也沒有重新安裝的麻煩。由於Java的設計原理,程序員只需要創建程序的一個版本,那個程序能在幾乎所有計算機以及安裝了Java解釋器的浏覽器中運行。由於Java是一種全功能的編程語言,所以在向服務器發出一個請求之前,我們能先在客戶端做完盡可能多的工作。例如,再也不必通過因特網傳送一個請求表單,再由服務器確定其中是否存在一個拼寫或者其他參數錯誤。大多數數據校驗工作均可在客戶端完成,沒有必要坐在計算機前面焦急地等待服務器的響應。這樣一來,不僅速度和響應的靈敏度得到了極大的提高,對網絡和服務器造成的負擔也可以明顯減輕,這對保障因特網的暢通是至關重要的。
與腳本程序相比,Java程序片的另一個優點是它采用編譯好的形式,所以客戶端看不到源碼。當然在另一方面,反編譯Java程序片也並不是件難事,而且代碼的隱藏一般並不是個重要的問題。大家要注意另外兩個重要的問題。正如本書以前會講到的那樣,編譯好的Java程序片可能包含了許多模塊,所以要多次“命中”(訪問)服務器以便下載(在Java 1.1中,這個問題得到了有效的改善——利用Java壓縮檔,即JAR文件——它允許設計者將所有必要的模塊都封裝到一起,供用戶統一下載)。在另一方面,腳本程序是作為Web頁正文的一部分集成到Web頁內的。這種程序一般都非常小,可有效減少對服務器的點擊數。另一個因素是學習方面的問題。不管你平時聽別人怎麼說,Java都不是一種十分容易便可學會的語言。如果你以前是一名Visual Basic程序員,那麼轉向VBScript會是一種最快捷的方案。由於VBScript可以解決大多數典型的客戶機/服務器問題,所以一旦上手,就很難下定決心再去學習Java。如果對腳本編制語言比較熟,那麼在轉向Java之前,建議先熟悉一下JavaScript或者VBScript,因為它們可能已經能夠滿足你的需要,不必經歷學習Java的艱苦過程。
4. ActiveX
在某種程度上,Java的一個有力競爭對手應該是微軟的ActiveX,盡管它采用的是完全不同的一套實現機制。ActiveX最早是一種純Windows的方案。經過一家獨立的專業協會的努力,ActiveX現在已具備了跨平台使用的能力。實際上,ActiveX的意思是“假如你的程序同它的工作環境正常連接,它就能進入Web頁,並在支持ActiveX的浏覽器中運行”(IE固化了對ActiveX的支持,而Netscape需要一個插件)。所以,ActiveX並沒有限制我們使用一種特定的語言。比如,假設我們已經是一名有經驗的Windows程序員,能熟練地使用象C++、Visual Basic或者BorlandDelphi那樣的語言,就能幾乎不加任何學習地創建出ActiveX組件。事實上,ActiveX是在我們的Web頁中使用“歷史遺留”代碼的最佳途徑。
5. 安全
自動下載和通過因特網運行程序聽起來就象是一個病毒制造者的夢想。在客戶端的編程中,ActiveX帶來了最讓人頭痛的安全問題。點擊一個Web站點的時候,可能會隨同HTML網頁傳回任何數量的東西:GIF文件、腳本代碼、編譯好的Java代碼以及ActiveX組件。有些是無害的;GIF文件不會對我們造成任何危害,而腳本編制語言通常在自己可做的事情上有著很大的限制。Java也設計成在一個安全“沙箱”裡在它的程序片中運行,這樣可防止操作位於沙箱以外的磁盤或者內存區域。
ActiveX是所有這些裡面最讓人擔心的。用ActiveX編寫程序就象編制Windows應用程序——可以做自己想做的任何事情。下載回一個ActiveX組件後,它完全可能對我們磁盤上的文件造成破壞。當然,對那些下載回來並不限於在Web浏覽器內部運行的程序,它們同樣也可能破壞我們的系統。從BBS下載回來的病毒一直是個大問題,但因特網的速度使得這個問題變得更加復雜。
目前解決的辦法是“數字簽名”,代碼會得到權威機構的驗證,顯示出它的作者是誰。這一機制的基礎是認為病毒之所以會傳播,是由於它的編制者匿名的緣故。所以假如去掉了匿名的因素,所有設計者都不得不為它們的行為負責。這似乎是一個很好的主意,因為它使程序顯得更加正規。但我對它能消除惡意因素持懷疑態度,因為假如一個程序便含有Bug,那麼同樣會造成問題。
Java通過“沙箱”來防止這些問題的發生。Java解釋器內嵌於我們本地的Web浏覽器中,在程序片裝載時會檢查所有有嫌疑的指令。特別地,程序片根本沒有權力將文件寫進磁盤,或者刪除文件(這是病毒最喜歡做的事情之一)。我們通常認為程序片是安全的。而且由於安全對於營建一套可靠的客戶機/服務器系統至關重要,所以會給病毒留下漏洞的所有錯誤都能很快得到修復(浏覽器軟件實際需要強行遵守這些安全規則;而有些浏覽器則允許我們選擇不同的安全級別,防止對系統不同程度的訪問)。
大家或許會懷疑這種限制是否會妨礙我們將文件寫到本地磁盤。比如,我們有時需要構建一個本地數據庫,或將數據保存下來,以便日後離線使用。最早的版本似乎每個人都能在線做任何敏感的事情,但這很快就變得非常不現實(盡管低價“互聯網工具”有一天可能會滿足大多數用戶的需要)。解決的方案是“簽了名的程序片”,它用公共密鑰加密算法驗證程序片確實來自它所聲稱的地方。當然在通過驗證後,簽了名的一個程序片仍然可以開始清除你的磁盤。但從理論上說,既然現在能夠找到創建人“算帳”,他們一般不會干這種蠢事。Java 1.1為數字簽名提供了一個框架,在必要時,可讓一個程序片“走”到沙箱的外面來。
數字簽名遺漏了一個重要的問題,那就是人們在因特網上移動的速度。如下載回一個錯誤百出的程序,而它很不幸地真的干了某些蠢事,需要多久的時間才能發覺這一點呢?這也許是幾天,也可能幾周之後。發現了之後,又如何追蹤當初肇事的程序呢(以及它當時的責任有多大)?
6. 因特網和內聯網
Web是解決客戶機/服務器問題的一種常用方案,所以最好能用相同的技術解決此類問題的一些“子集”,特別是公司內部的傳統客戶機/服務器問題。對於傳統的客戶機/服務器模式,我們面臨的問題是擁有多種不同類型的客戶計算機,而且很難安裝新的客戶軟件。但通過Web浏覽器和客戶端編程,這兩類問題都可得到很好的解決。若一個信息網絡局限於一家特定的公司,那麼在將Web技術應用於它之後,即可稱其為“內聯網”(Intranet),以示與國際性的“因特網”(Internet)有別。內聯網提供了比因特網更大的安全級別,因為可以物理性地控制對公司內部服務器的使用。說到培訓,一般只要人們理解了浏覽器的常規概念,就可以非常輕松地掌握網頁和程序片之間的差異,所以學習新型系統的開銷會大幅度減少。
安全問題將我們引入客戶端編程領域一個似乎是自動形成的分支。若程序是在因特網上運行,由於無從知曉它會在什麼平台上運行,所以編程時要特別留意,防范可能出現的編程錯誤。需作一些跨平台處理,以及適當的安全防范,比如采用某種腳本語言或者Java。
但假如在內聯網中運行,面臨的一些制約因素就會發生變化。全部機器均為Intel/Windows平台是件很平常的事情。在內聯網中,需要對自己代碼的質量負責。而且一旦發現錯誤,就可以馬上改正。除此以外,可能已經有了一些“歷史遺留”的代碼,並用較傳統的客戶機/服務器方式使用那些代碼。但在進行升級時,每次都要物理性地安裝一道客戶程序。浪費在升級安裝上的時間是轉移到浏覽器的一項重要原因。使用了浏覽器後,升級就變得易如反掌,而且整個過程是透明和自動進行的。如果真的是牽涉到這樣的一個內聯網中,最明智的方法是采用ActiveX,而非試圖采用一種新的語言來改寫程序代碼。
面臨客戶端編程問題令人困惑的一系列解決方案時,最好的方案是先做一次投資/回報分析。請總結出問題的全部制約因素,以及什麼才是最快的方案。由於客戶端程序設計仍然要編程,所以無論如何都該針對自己的特定情況采取最好的開發途徑。這是准備面對程序開發中一些不可避免的問題時,我們可以作出的最佳姿態。