編程|進階 4.3.3 執行其他的網頁
ASP 3.0和IIS 5.0的新特性之一就是引入了可程式化的伺服器端重新導向(server-side redirection)的概念。這意味著,可以把一個網頁的控制和執行轉到另外一個網頁,而不需要在用戶端使用Response.Rdedirect方法。
1. 用戶端重新導向帶來的問題
ASP編程人員通常使用Response.Redirect語句把一個頁面載入到當前正在執行的網頁。然而,許多人沒有意識到這條語句不會自動地使伺服器立即裝入和執行新的網頁。其真正做的是把一個HTTP重新導向前序(redirection header)增加到由Web伺服器發送給客戶的輸出資料流中。這個前序如下:
HTTP/1.1 302 Object Moved
Location newpage.asp
在這個前序中的標準HTTP狀態資訊“302 Object Moved”,告知瀏覽器所要求的資源已經發生移動。Location前序提供相應的網頁地址。當然這個地址不一定是真實的,現在正在做的事情就是“欺騙”瀏覽器,使瀏覽器認為可在另一個位置上找到所需要的網頁。實際發生的是,伺服器將執行所請求的網頁,但是通知瀏覽器需要的網頁已經發生移動。這就是在發送任何頁面的內容到瀏覽器之前必須執行Redirect方法的原因。
當一個瀏覽器接受到“302 Object Moved”資訊時,中斷當前的請求並為Location值中指定的網頁發送一個新的請求。這與在網頁的<HEAD>段使用一個META HTTP-EQUIV標記時的工作方式相同,前面給出的HTTP前序還可寫為:
<META HTTP-EQUIV=”REFRESH” CONTENT=”0;URL=newpage.asp”>
因此重新導向實際上發生在客戶機端,而不是在伺服器上。如果在這個串連的用戶端有一個Proxy 伺服器在使用的話,可能會引起顯示虛假訊息。這就是在使用Response.Redirect時,“The object you requested has been moved and can be found here”訊息經常在客戶機上顯示的原因,正確地使用緩衝通常可以防止這個問題。
在IIS 4.0或更早的版本中使用Response.Redirect時,應該在ASP網頁的開頭開啟緩衝,然後在執行Response.Redirect方法之前調用Response.Clear。當然,在ASP 3.0中網頁緩衝的預設狀態為開啟,因此這不成問題。只要在執行該語句之前使用Response.Clear,以前產生的輸出將不會發送給客戶。
2. 在ASP 3.0中伺服器端的重新導向
在ASP 3.0和IIS 5.0中,在幾乎所有情況下,通過使用兩個新的Server對象方法Execute和Transfer,可以避免使用用戶端重新導向。這兩個方法使控制立即轉到另一個網頁,該網頁可以是一個ASP網頁或者是任何其他的資源,例如一個HTTP網頁、壓縮檔或其他類型的檔案。
它們之間的不同之處是:Execute方法“調用”另一個的網頁,與在指令碼代碼中調用一個子程式或函數非常相似。當另一個網頁或資源已經執行完畢或傳送到用戶端時,控制返回到原網頁中調用Execute方法的語句的下一條語句,並繼續執行。而使用Transfer方法時,控制不再返回到原頁面中,在控制傳送到的網頁或資源的末尾處,執行過程停止。
當前網頁的環境也傳送給了目標網頁或資源,因此這兩個方法更有用。網頁環境包含了原有的ASP對象中的所有變數的值,例如Request、Response和Session對象的集合以及它們的所有屬性。即使該網頁不在同一個虛擬應用程式中,也將傳送Application對象的環境。
結果是瀏覽器認為它仍在接收原先的頁面,它並不瞭解伺服器所做的事情。瀏覽器的地址欄一直顯示相同的URL,並且Back、Forward和Refresh按鈕正常地工作。在使用用戶端重新導向時,尤其是使用HTML META元素時,情況通常不是這樣的。
傳送到新的頁面或資源的環境包括所有現存的事務狀態(transaction state)。當前網頁的環境用ASP的ObjectContext對象(在第1章中已經討論過)進行封裝。如果需要將這個對象作為一個進行中的事務的一部分,可以在傳送控制的目的頁面中使用這個對象。
(1) Server對象的Execute和Transfer方法的使用
在前面的樣本頁面中,可以實驗使用Excute和Transfer方法。該頁麵包含了在樣本中已經提供的另一個檔案名稱字another_page.asp,它作為這兩個方法的預設參數值,如圖4-13所示:
圖4-13 使用Execute和Transfer方法的螢幕
單擊Server.Execute和Server.Transfer方法的按鈕,提交到此表單並重新裝載該表單。在這個頁面頂部的指令碼代碼查看是哪個按扭被單擊。如果是cmdExecute或cmdTransfer按鈕,則把當前網頁的路徑寫入到輸出資料流中,然後調用相應的方法,並傳送與該按鈕相聯絡的文字框中的值,然後再把當前頁面的路徑寫到輸出資料流中。
…
If Len(Request.Form("cmdExecute")) Then
strPath = Request.Form("txtExecPath")
Response.Write "Currently executing the page: <B>" _
& Request.ServerVariables("SCRIPT_NAME") & "</B><BR>"
Server.Execute (strPath)
Response.Write "Currently executing the page: <B>" _
& Request.ServerVariables("SCRIPT_NAME") & "</B><BR>"
End If
If Len(Request.Form("cmdTransfer")) Then
strPath = Request.Form("txtTransferPath")
Response.Write "Currently executing the page: <B>" _
& Request.ServerVariables("SCRIPT_NAME") & "</B><BR>"
Server.Transfer (strPath)
End If
…
當單擊Server.Excute方法的按鈕時,會看到當前頁面的路徑,這是由上面代碼中的第一條Response.Write語句建立並顯示的。後面接著的內容是來自被執行的網頁(another_page.asp)的一些輸出內容。在這之後是第二個Response.Write語句的輸出內容,這表明控制又回到了原先的網頁,螢幕如圖4-14所示:
圖4-14 Server.Excute方法的示範
頁面的兩條水平線之間的段落(顯示當前執行的網頁為show_server.asp)來自原先的網頁。在接下來的段落來自被執行的網頁another_page.asp。下面是該頁面的完整代碼:
<%@ LANGUAGE=VBSCRIPT %>
<HR>
Currently executing the page: <B>another_page.asp</B><BR>
However the value of <B>Request.ServerVariables("SCRIPT_NAME")</B> is still <BR>
<B><% = Request.ServerVariables("SCRIPT_NAME") %></B>
because the <B>Request</B> collections hold<BR>
the same values as they had in the page that executed thi