?? chapter15.htm
字號:
<br>
15.5.3 要注意的問題<br>
前面采取的似乎是一種完美的方法。沒有CGI編程,所以在服務器啟動一個CGI程序時不會出現延遲。數據報方式似乎能產生非常快的響應。此外,一旦Java
1.1得到絕大多數人的采納,服務器端的那一部分就可完全用Java編寫(盡管利用標準輸入和輸出同一個非Java程序連接也非常容易)。<br>
但必須注意到一些問題。其中一個特別容易忽略:由于Java應用在服務器上是連續運行的,而且會把大多數時間花在Datagram.receive()方法的等候上面,這樣便為CPU帶來了額外的開銷。至少,我在自己的服務器上便發現了這個問題。另一方面,那個服務器上不會發生其他更多的事情。而且假如我們使用一個任務更為繁重的服務器,啟動程序用“nice”(一個Unix程序,用于防止進程貪吃CPU資源)或其他等價程序即可解決問題。在許多情況下,都有必要留意象這樣的一些應用——一個堵塞的receive()完全可能造成CPU的癱瘓。<br>
第二個問題涉及防火墻。可將防火墻理解成自己的本地網與因特網之間的一道墻(實際是一個專用機器或防火墻軟件)。它監視進出因特網的所有通信,確保這些通信不違背預設的規則。<br>
防火墻顯得多少有些保守,要求嚴格遵守所有規則。假如沒有遵守,它們會無情地把它們拒之門外。例如,假設我們位于防火墻后面的一個網絡中,開始用Web瀏覽器同因特網連接,防火墻要求所有傳輸都用可以接受的http端口同服務器連接,這個端口是80?,F在來了這個Java程序片NameSender,它試圖將一個數據報傳到端口8080,這是為了越過“受保護”的端口范圍0-1024而設置的。防火墻很自然地把它想象成最壞的情況——有人使用病毒或者非法掃描端口——根本不允許傳輸的繼續進行。<br>
只要我們的客戶建立的是與因特網的原始連接(比如通過典型的ISP接駁Internet),就不會出現此類防火墻問題。但也可能有一些重要的客戶隱藏在防火墻后,他們便不能使用我們設計的程序。<br>
在學過有關Java的這么多東西以后,這是一件使人相當沮喪的事情,因為看來必須放棄在服務器上使用Java,改為學習如何編寫C或Perl腳本程序。但請大家不要絕望。<br>
一個出色方案是由Sun公司提出的。如一切按計劃進行,Web服務器最終都裝備“小服務程序”或者“服務程序片”(Servlet)。它們負責接收來自客戶的請求(經過防火墻允許的80端口)。而且不再是啟動一個CGI程序,它們會啟動小服務程序。根據Sun的設想,這些小服務程序都是用Java編寫的,而且只能在服務器上運行。運行這種小程序的服務器會自動啟動它們,令其對客戶的請求進行處理。這意味著我們的所有程序都可以用Java寫成(100%純咖啡)。這顯然是一種非常吸引人的想法:一旦習慣了Java,就不必換用其他語言在服務器上處理客戶請求。<br>
由于只能在服務器上控制請求,所以小服務程序API沒有提供GUI功能。這對NameCollector.java來說非常適合,它本來就不需要任何圖形界面。<br>
在本書寫作時,java.sun.com已提供了一個非常廉價的小服務程序專用服務器。Sun鼓勵其他Web服務器開發者為他們的服務器軟件產品加入對小服務程序的支持。<br>
<br>
15.6 Java與CGI的溝通<br>
Java程序可向一個服務器發出一個CGI請求,這與HTML表單頁沒什么兩樣。而且和HTML頁一樣,這個請求既可以設為GET(下載),亦可設為POST(上傳)。除此以外,Java程序還可攔截CGI程序的輸出,所以不必依賴程序來格式化一個新頁,也不必在出錯的時候強迫用戶從一個頁回轉到另一個頁。事實上,程序的外觀可以做得跟以前的版本別無二致。<br>
代碼也要簡單一些,畢竟用CGI也不是很難就能寫出來(前提是真正地理解它)。所以在這一節里,我們準備辦個CGI編程速成班。為解決常規問題,將用C++創建一些CGI工具,以便我們編寫一個能解決所有問題的CGI程序。這樣做的好處是移植能力特別強——即將看到的例子能在支持CGI的任何系統上運行,而且不存在防火墻的問題。<br>
這個例子也闡示了如何在程序片(Applet)和CGI程序之間建立連接,以便將其方便地改編到自己的項目中。<br>
<br>
15.6.1 CGI數據的編碼<br>
在這個版本中,我們將收集名字和電子函件地址,并用下述形式將其保存到文件中:<br>
First Last <email@domain.com>;<br>
這對任何E-mail程序來說都是一種非常方便的格式。由于只需收集兩個字段,而且CGI為字段中的編碼采用了一種特殊的格式,所以這里沒有簡便的方法。如果自己動手編制一個原始的HTML頁,并加入下述代碼行,即可正確地理解這一點:<br>
<br>
865頁程序<br>
<br>
上述代碼創建了兩個數據輸入字段(區),名為name和email。另外還有一個submit(提交)按鈕,用于收集數據,并將其發給CGI程序。Listmgr2.exe是駐留在特殊程序目錄中的一個可執行文件。在我們的Web服務器上,該目錄一般都叫作“cgi-bin”(注釋③)。如果在那個目錄里找不到該程序,結果就無法出現。填好這個表單,然后按下提交按鈕,即可在瀏覽器的URL地址窗口里看到象下面這樣的內容:<br>
http://www.myhome.com/cgi-bin/Listmgr2.exe?name=First+Last&email=email@domain.com&submit=Submit<br>
<br>
③:在Windows32平臺下,可利用與Microsoft Office 97或其他產品配套提供的Microsoft
Personal Web Server(微軟個人Web服務器)進行測試。這是進行試驗的最好方法,因為不必正式連入網絡,可在本地環境中完成測試(速度也非??欤?。如果使用的是不同的平臺,或者沒有Office
97或者FrontPage 98那樣的產品,可到網上找一個免費的Web服務器供自己測試。<br>
<br>
當然,上述URL實際顯示時是不會拆行的。從中可稍微看出如何對數據編碼并傳給CGI。至少有一件事情能夠肯定——空格是不允許的(因為它通常用于分隔命令行參數)。所有必需的空格都用“+”號替代,每個字段都包含了字段名(具體由HTML頁決定),后面跟隨一個“=”號以及正式的字段數據,最后用一個“&”結束。<br>
到這時,大家也許會對“+”,“=”以及“&”的使用產生疑惑。假如必須在字段里使用這些字符,那么該如何聲明呢?例如,我們可能使用“John
& MarshaSmith”這個名字,其中的“&”代表“And”。事實上,它會編碼成下面這個樣子:<br>
John+%26+Marsha+Smith<br>
也就是說,特殊字符會轉換成一個“%”,并在后面跟上它的十六進制ASCII編碼。<br>
幸運的是,Java有一個工具來幫助我們進行這種編碼。這是URLEncoder類的一個靜態方法,名為encode()??捎孟率龀绦騺碓囼炦@個方法:<br>
<br>
866頁程序<br>
<br>
該程序將獲取一些命令行參數,把它們合并成一個由多個詞構成的字串,各詞之間用空格分隔(最后一個空格用String.trim()剔除了)。隨后對它們進行編碼,并打印出來。<br>
為調用一個CGI程序,程序片要做的全部事情就是從自己的字段或其他地方收集數據,將所有數據都編碼成正確的URL樣式,然后匯編到單獨一個字串里。每個字段名后面都加上一個“=”符號,緊跟正式數據,再緊跟一個“&”。為構建完整的CGI命令,我們將這個字串置于CGI程序的URL以及一個“?”后。這是調用所有CGI程序的標準方法。大家馬上就會看到,用一個程序片能夠很輕松地完成所有這些編碼與合并。<br>
<br>
15.6.2 程序片<br>
程序片實際要比NameSender.java簡單一些。這部分是由于很容易即可發出一個GET請求。此外,也不必等候回復信息?,F在有兩個字段,而非一個,但大家會發現許多程序片都是熟悉的,請比較NameSender.java。<br>
<br>
867-869頁程序<br>
<br>
CGI程序(不久即可看到)的名字是Listmgr2.exe。許多Web服務器都在Unix機器上運行(Linux也越來越受到青睞)。根據傳統,它們一般不為自己的可執行程序采用.exe擴展名。但在Unix操作系統中,可以把自己的程序稱呼為自己希望的任何東西。若使用的是.exe擴展名,程序毋需任何修改即可通過Unix和Win32的運行測試。<br>
和往常一樣,程序片設置了自己的用戶界面(這次是兩個輸入字段,不是一個)。唯一顯著的區別是在action()方法內產生的。該方法的作用是對按鈕按下事件進行控制。名字檢查過以后,大家會發現下述代碼行:<br>
<br>
869-870頁程序<br>
<br>
name和email數據都是它們對應的文字框里提取出來,而且兩端多余的空格都用trim()剔去了。為了進入列表,email名字被強制換成小寫形式,以便能夠準確地對比(防止基于大小寫形式的錯誤判斷)。來自每個字段的數據都編碼為URL形式,隨后采用與HTML頁中一樣的方式匯編GET字串(這樣一來,我們可將Java程序片與現有的任何CGI程序結合使用,以滿足常規的HTML
GET請求)。<br>
到這時,一些Java的魔力已經開始發揮作用了:如果想同任何URL連接,只需創建一個URL對象,并將地址傳遞給構建器即可。構建器會負責建立同服務器的連接(對Web服務器來說,所有連接行動都是根據作為URL使用的字串來判斷的)。就目前這種情況來說,URL指向的是當前Web站點的cgi-bin目錄(當前Web站點的基礎地址是用getDocumentBase()設定的)。一旦Web服務器在URL中看到了一個“cgi-bin”,會接著希望在它后面跟隨了cgi-bin目錄內的某個程序的名字,那是我們要運行的目標程序。程序名后面是一個問號以及CGI程序會在QUERY_STRING環境變量中查找的一個參數字串(馬上就要學到)。<br>
我們發出任何形式的請求后,一般都會得到一個回應的HTML頁。但若使用Java的URL對象,我們可以攔截自CGI程序傳回的任何東西,只需從URL對象里取得一個InputStream(輸入數據流)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -