全域變數的考量

来源:岁月联盟 编辑:zhuzhu 时间:2003-07-11
當我們利用Visual Basic在製作Client-Server架構的應用程式時,如果遇到需要跨表單傳遞的變數或者是常數,我們可以利用module的方式設定全域的變數。但是在Web Application中要使用全域變數,就沒有那麼容易了。HTTP是一個無狀態(stateless)的通訊協定,伺服器只能和使用者建立要求(Request)和回應(Response)的關係,並無法為使用者保留工作階段中的狀態。如果要傳遞參數的話,我們只能用表單(Form)或URL String的方式去傳遞。這樣的傳遞方式會有其限制:首先,如果是關於整個應用程式的一些系統變數或常數,我們必須要有一個機制,使得使用者一登入時就可以得到這些環境變數。而表單或URL字串的需要先將資料存放在資料庫或其他儲存的機制中,當使用者登入該檔案時才能獲得。但是我們知道,系統變數是可以隨著應用程式的執行而改變的,使用表單或URL的字串我們必須要在程式傳遞時去考慮這些變數。例如一個網站的記數器的總人數,如果我們利用文字檔來製作的話,我們必須常常去開啟該文字檔,造成程式執行效率不佳。 再者,如果我們將所有的ASP程式之前都加入表單來傳遞參數的話,當這些參數在網路上傳遞時,都會有被人擷取的安全考量。因此,若能由伺服器端提供一個機制來傳遞這一類全域變數,這些問題都將可以解決。 ASP Engine提供了兩個Server端的物件供我們做全域參數的傳遞,Application物件以及Session物件。Session物件將在後面的章節中再做說明,讓我們先看看Application物件。
Application物件在我們使用Application物件之前,我們必須先了解Application物件所定義的範圍。當使用者開啟一個Web Application時,IIS會根據該應用程式的啟動點去開啟對應的Global.asa檔案。因此我們可以將應用程式所需要定義的一些全域變數或者是全域的物件變數定義在這個檔案中,一方面方便管理,一方面也可以確定使用者一定會擁有這一些全域變數可以使用。而在Global.asa中除了設定變數外,還會觸發Application物件的兩個事件:Application_OnStart以及Application_OnEnd。 l.Application_OnStart Web Application是以檔案的方式儲存在伺服器中,因此當你將一個開發好的Web Application放置在伺服器時,應用程式並不會自動去執行。而當第一個使用者開啟應用程式中的ASP檔案時,此時才是應用程式開始執行的時機。因此,當第一個使用者開啟應用程式中的ASP檔案時,會一並觸發Global.asa中的Application_OnStart事件。對於整個應用程式的執行階段而言,這個事件只會被觸發一次,因次我們可以將應用程式中的一些環境變數的初始值在這個事件中設定。2.Application_OnEnd一但應用程式啟動,我們希望伺服器中的應用程式得以不間斷的回應使用者的需求。因此,除非是我們將伺服器關閉,否則是無法觸發這一個事件的,即使是系統當機亦然。因此如果希望能當IIS關閉時能將工作階段中的值寫入儲存機制的話,我們可以將程式碼寫在這一個事件中。但是若是系統當機的話是不會觸發這一個事件的,所以如果是比較重要的變數資料可以考慮在別的地方儲存。因此,一旦設定一個Application的變數,它的執行範圍將是從第一隻ASP檔案由使用者開啟之後就存在一直到IIS關機為止。如果我們要將一個資料儲存到Application物件中呢,我們必須先給這個資料一個Key值,如果要從程式中取出資料就需要利用到這個Key值。我們可以在Application_OnStart事件中加入如下的程式碼:Sub Application_onstart
Application("count")=0 EndSub 此時我們將一個Key值為 "count" 的Application設為0。而因為我們是寫在Application_OnStart中,因此當第一個使用者開啟應用程式中第一個ASP檔案時,這個Application變數也會跟著產生。我們可以在我們的應用程式中任一個ASP檔案去讀取這一個值。例如我們可以在Default.asp中加入下列程式:Response.Write Application ("counter") 這樣我們將會把Application("counter")這一個變數值顯示在使用者端。而我們也可以在ASP程式中對Application變數做修改。但是在修改Application變數時需要注意,Application變數是針對整個應用程式都有效的,當你在修改時若有其他使用者正在讀取,會導致資料不一致的問題。因此,當需要修改Application變數時,我們必須先將Application物件中的資料鎖定,修改完成之後再將其釋放。使用Application物件中的Lock方法可以讓我們將Application物件鎖定,而使用Unlock方法可以把Alpplication物件的鎖定解除。所以如果我們要做到當使用者登入到首頁時記數器加一的功能時,我們的程式碼應該這樣寫:Application.Lock Application("count")=
Application("count") + 1
Application.Unlock Session物件全域變數除了供所有使用應用程式的使用者使用的Application變數外,還有一種變數是根據使用者而改變的。前面曾經說過,因為HTTP是無狀態的通訊協定,因此需要由使用者的要求與伺服器的回應才能建立起一個工作階段(Session)。跟Application物件不同的是,每一個使用者的工作階段都可以在伺服器端建立一個Session物件,而我們的伺服器端該如何去識別這些不同使用者建立的Session呢?1. Session_OnStart當使用者開啟Web Application中第一個ASP檔案時,會觸發Global.asa中的Session_OnStart事件,並且開啟一個屬於該工作階段的Session物件。為了識別,每個Session都會有一個SessionID,這一個SessionID會夾在一個Cookie中送到使用者端。爾後只要Client端的瀏覽器沒有關閉,這個Cookie都會一直存在,所以我們的伺服器就可以根據這個Cookie值來判斷使用者的工作階段。剛剛記數器的例子之中,我們將記數器加一的程式放在Default.asp當中。這樣雖然可以在使用者登入時就去將記數器的數目增加,但是若是使用者重新整理視窗時,記數器就無法正去正確的去計算了。因此,若要正確的計算上站瀏覽過的人數,我們必須在使用者登入時就去做計算的動作。所以我們把原先放在Default.asp中的程式移到Glogal.asa中的Session_OnStart事件中:Sub Session_OnStart
Application.Lock
Application("count")= Application("count") + 1
Application.Unlock
End Sub 2.Session_OnEndSession_OnEnd的觸發時機並不是當使用者關閉瀏覽器的時候去觸發,因為伺服器並沒有辦法去偵測使用者是否關閉瀏覽器。所以伺服器只能針對使用者有多久沒有對伺服器發出要求,來判斷工作階段是否該結束。Session物件有一個Timeout的屬性,可以設定當使用者多久沒有發出要求時,就去把Session物件結束並釋放記憶體。這一個屬性也可以從IIS做設定。
Session物件還有一個Abandon的方法,當你執行Session.Abandon時,伺服器會立刻使用者的Session物件摧毀。同時也一樣會去觸發Session_OnEnd事件。這時所有的Session變數都會消失,所以我們無法針對某一個Session變數下Abandon的指令。
使用Session物件,我們並無法正確的偵測使用者真正的離線時間,所以這個時候我們如果要計算網站中實際的上線人數,我們無法用Session的方式做到,但是當設計個人化網站時,我們仍然可以利用Session_OnEnd的事件來儲存使用者之工作階段或個人化之設定。 Server物件使用ASP開發網際網路應用程式最大的好處就是它的擴充性,我們可以利用Server物件來實例(Instance)COM物件的實例,達到我們需要的功能。在ASP 3.0中Server物件新增了兩個方法:Server.Transfer以及Server.Execute。1. Server.Transfer在ASP 2.0中,我們如果要在Web Application執行時轉到另一頁執行其他的ASP程式,我們必須使用Response.Redirect的方式。在ASP 3.0中,除了Response.Redirect之外,我們還可以使用Server.Transfer的方式。兩者的不同在於:使用Response.Redirect的方式,當程式執行到Response.Redirect時,會先將轉址的訊息通知Client的瀏覽器,同時將伺服器上的工作佇列移掉,再由使用者端的瀏覽器向伺服器發出新的HTTP要求,然後再由伺服器產生新的工作佇列來顯示網頁。
圖一 若是換成Server.Transfer的方式執行,則當執行至Server.Transfer,伺服器會直接將轉址的要求傳到程式要求的那一頁。先前的工作階段將會被保留。
圖二我們試試下面的程式碼: 首先產生一個使用者輸入的頁面Login.asp: < Form name="form1" id="form1" action="Check.asp" method="post" >
Name:< Input type="text" name="tName" id="tName" >
Password:< Input type="password" name="pName"id="pName" >
< Input type="submit" value="Click me!!" >< /Form > 接者產生一頁Check.asp來驗證:< %
Response.Buffer = True
StrName = Request.Form ( "tName" )
StrPassword = Request.Form ( "pName" )
Response.Write "用Response.Redirect看不到這一行
" If strName = " John " and strPassword = "1234" then
Response.Redirect "OK.asp" Else
Response.Redirect " Error.asp " End If Response.Write " 如果你用Server.Execute方式,將會看到這一行 "
% > 驗證通過顯示OK.asp:< HTML >
< BODY >
這是驗證通過的頁面!!!
< /BODY > < /HTML > 驗證失敗顯示Error.asp:< HTML >
< BODY > 這是驗證失敗的頁面!!! 請輸入使用者:John
請輸入密碼:1234 < /BODY >< /HTML > 輸入登入資料後結果如下:
圖三 執行後會發現,在Check.asp前面的那一行文字並不會出現。若我們將Response.Redirect換成Server.Transfer,將會得到不一樣的結果
圖四 n Server.Execute 和Server.Execute相似,但是在下一頁執行完之後會將結果傳回Check.asp。
圖五 把Check.asp中的Server.Transfer換成Server.Execute之後,結果如下:
圖六 由此可以看到這幾種方式使用的比較。用Server.Transfer或Server.Execute的方式轉送頁面的話,可以減少伺服器端的工作佇列的使用以及獲得更好的頻寬。但是這兩種方法還是有其先天的限制:無法跨機器執行。也就是你無法去執行另一台伺服器中的檔案,因為記憶體中的資料無法跨機器傳遞。
在前面有提到,使用ASP的Server物件,我們的ASP程式將可以有強大的擴充的能力。這是因為當我們使用Server.CreateObject("ProgID")的方式可以將一個元件實例(Instance)到我們的程式中。而所謂的實例,大家可以想想成就是我們可以引用這些元件的屬性或方法,來增加我們程式的功能的一種方式 。 我們可以利用一個Server端的FileSystemObject元件來學習如何使用元件。FileSystemObject或許大家沒聽過,但是他曾出現在大名鼎鼎的 "I Love You" 病毒中,為各位刪除檔案,因此中毒的機器檔案都會消失。利用FileSystemObject我們可以製作出我們自己的檔案總管,因為這一個元件本身就是用來對機器中的檔案做新增、修改、刪除的工作的。如果說我們今天想要把記數器中的資料寫到一個檔案中,我們可以使用FileSystemObject:< %
Set objFSO =
Server.CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("c:/counter.txt", True)
objFile.WriteLine(Application("count"))
objFile.Close
% > 這時會在伺服器的電腦的C碟根目錄產生一個 "Counter.txt" 的文字檔,並且會將目前的記數資料從到文字檔中。如果我們希望在應用程式開始時就能載入前一次關閉時的總人數,我們可以在Application_OnStart的事件中,從這一個文字檔中去讀取上次應用程式關閉之前的總人數:Sub Application_OnStart
Set objFSO =
Server.CreateObject("Scripting.FileSystemObject")
Set objFile =
objFSO.OpenTextFile("c:/counter.txt",1,True)
Application("count")= objFile.ReadLine
objFile.Close
End Sub 在使用Server.CreateObject時,會根據註冊在電腦中的元件的Program ID來決定要取出哪一個物件。所以如果我們要擴充我們伺服器的功能,我們必須要先了解元件的功能,或者是我們必須要自己去開發元件。無論是要使用ASP程式發送信件,或者是要使用ASP程式存去網域中使用者的資料,我們都可以利用元件為我們做到想要的功能。武俠小說中我們常常會聽到,一個練武的人,如果沒有打通任督二脈的話,是練不成上乘的武功的。在Web Application的領域中,ASP物件就像是伺服器端的任督二脈,如果我們無法善用這幾個物件的話,一定無法做出好的解決方案。尤其如果我們善用Server物件的擴充性的話,幾乎所有以前Client-Server架構程式中的功能我們都能做得到。在電子商務的程式開發中,我們更可以利用ASP物件結合後端的資料庫來製作個人化的網頁,或者是利用Office Web Component來製作商業報表。因此,在看完這些ASP物件的使用方式之後,希望大家多練習ASP元件的基本功,早日打通任督二脈,朝向更深一層的領域中發展。