6-12:Remote Scripting

     
Web 基本上事一個分散的系統,所有的計算和處理,都由用戶端和伺服器來共同完成,用戶端的電腦執行的是網頁中的 client script,而伺服器則是執行網頁中的 server scripts。在 http 的協定下,每當使用者發出一個 request 之後,伺服器就相執行網頁中的 server scripts (如 ASP),並將結果傳回給用戶端,再由用戶端的瀏覽器來執行網頁中的 client scripts(如 JavaScript 或 VBScript),並將結果顯示在螢幕上。如果還要存取伺服器端的資料,就必須再一次經由表單的送出,才能指揮伺服器做事,並將結果以新的網頁回傳,因此要保存原先網頁的資訊(或狀態)就比較麻煩,因而造成網頁流程設計的困難。因此,我們是否能由 client scripts 所接收的事件(如滑鼠點選某一按鈕)來指揮 server scripts 做事,並在不更動網頁的情況下,將 server scripts 的執行結果悄悄地送回 client scripts?答案是肯定的:請用 Remote Scripting。

Remote Scripting(遠端 Scripting,或簡稱 RS)是微軟新近提出的新概念,它的特點是可以讓用戶端的程式碼(JavaScript 或 VBScript)直接和伺服器端的程式碼溝通,而不必像一般 CGI 或 ASP,需經由頁面的回傳才能取得伺服器的執行結果。Remote Scripting 可以提供下列好處:

  1. 不必更新用戶端的網頁即可獲得伺服器端的執行結果,可簡化網頁流程設計。
  2. 不必在不同網頁之間傳遞變數,可降低網路流量。

Remote Scripting 的流程如下:

  1. 在用戶端呼叫伺服器端的 ASP 程式碼所定義的一個方法。
  2. 此 request 將經由一個代理程序(Proxy process)而送到伺服器。目前這個代理程序事實上是一個 Java applet,它會將用戶端的 request 送到伺服器,並將執行結果包成一個物件傳回用戶端。此物件稱為 Call object,它包含的伺服器執行的結果以及相關的資訊。
Remote Scripting 執行的方式可分兩種: 你可以依需要,選用不同的執行方式,以配合應用程式需求及網路速度。

下載並安裝 RS 後,會有下列三個檔案,分別說明如下:

  1. Rs.htm:這是和 RS 相關的用戶端 JavaScript 程式碼,需被用在 RS Client Script。
  2. Rsproxy.class:以 Java applet 形式存在的代理程序,需被用在 RS 的 Client Script。
  3. Rs.asp:和 RS 相關的伺服器端程式碼,定義了 RS Client Script 可呼叫之方法。
(事實上,你可以不用去瞭解這三個檔案的內容,除非你想知道內部的實作方式。)

使用 RS 的第一個步驟,必須先在 client script 啟動 RS,包含兩個動作:

上述兩段程式碼,均假設你是將 RS 安裝在伺服器根目錄下的 _ScriptLibrary。若是 _ScriptLibrary 放在其他位置,我們也可以用絕對或相對路徑來指明其位置。因此一個在用戶端的典型網頁,可以顯示如下:

上述範例的完整原始檔案 (showTime.htm) 如下:

<html>
<head>
<title>最簡單的 RS 範例:顯示 Client 和 Server 的時間</title>
</head>
<body>

<script src="_ScriptLibrary/RS.HTM"></script>
<script>RSEnableRemoteScripting("_ScriptLibrary")</script>

<script>
function getTime() {
	today = new Date();
	hour = today.getHours();
	minute = today.getMinutes();
	second = today.getSeconds();
	prepand = (hour>=12)? "下午":"上午";
	hour = (hour>=12)? hour-12:hour;
	str = "現在是"+prepand+hour+"點"+minute+"分"+second+"秒";
	return(str);
}
function getServerTime() {
	var serverURL = "showTimeServer.asp";
	var co = RSExecute(serverURL, "getServerTime");
	str = co.return_value+""; //convert to string
	return(str);
}
</script>

<h2 align=center>最簡單的 RS 範例:顯示 Client 和 Server 的時間</h2>
<hr>

範例:
<ul>
<li><a href="javascript:alert('Client time: ' + getTime())">顯示 Client 時間</a>
<li><a href="javascript:alert('Server time: ' + getServerTime())">顯示 Server 時間</a>
<li><a href="tShowTime.asp">測試 RS 所用的網頁</a>
</ul>
原始碼:
<ul>
<li><a href="/jang/books/webprog/common/showcode.asp?source=/jang/books/webprog/06asp/example/rs/showTime.htm">顯示 Client 端網頁:showTime.htm</a>
<li><a href="/jang/books/webprog/common/showcode.asp?source=/jang/books/webprog/06asp/example/rs/showTimeServer.asp">顯示 Server 端網頁:showTimeServer.asp</a>
<li><a href="/jang/books/webprog/common/showcode.asp?source=/jang/books/webprog/06asp/example/rs/tShowTime.asp">顯示測試 RS 所用的網頁:tShowTime.asp</a>
</ul>

<hr>
<script language="JavaScript">
function viewSource() {window.location="view-source:"+window.location} </script>

View source:
[<a href="/jang/books/webprog/common/showcode.asp?source=/jang/books/webprog/06asp/example/rs/showTime.htm">Server script</a>]
[<a href="javascript:viewSource()">Client script</a>]
<br>
Back to <a href="/jang/books/webprog/06asp/">ASP 線上中文手冊</a>

<a href="/jang/sandbox/asp/lib/editfile.asp?FileName=/jang/books/webprog/06asp/example/rs/showTime.htm"><img align=right border=0 src="/jang/graphics/invisible.gif"></a>

</body>
</html>
對於上述的 client script,我們在伺服器端有相對應的 server script,完整原始檔案 (showTimeServer.asp) 如下:
<%@ LANGUAGE=VBSCRIPT %>
<%  RSDispatch %>

<!--#INCLUDE file="_ScriptLibrary/rs.asp"-->

<SCRIPT RUNAT=SERVER Language=javascript>
function Description() { 
	this.getServerTime = getTime;
}
public_description = new Description();

function getTime() {
	today = new Date();
	hour = today.getHours();
	minute = today.getMinutes();
	second = today.getSeconds();
	prepand = (hour>=12)? "下午":"上午";
	hour = (hour>=12)? hour-12:hour;
	str = "現在是"+prepand+hour+"點"+minute+"分"+second+"秒";
	return(str);
}
</SCRIPT>
請注意在上述範例中,位於 showTime.htm 中的 getTime() 函數所產生的時間是由 JavaScript 讀取用戶端電腦的時間,而位於 showTime.htm 中的 getServerTime() 會呼叫 showTimeServer.asp 中的 getTime() 以取得伺服器的時間,並將結果傳回 showTime.htm,整個過程並不需要對 showTime.htm 進行換頁的工作。很明顯的,由用戶端和伺服器端所得到的時間並不一定會完全一致。

在使用 RS 的程式設計過程中,由於資料的傳遞是經由 Java,所以若有錯誤發生,常常較難進行除錯。一個簡單的除錯方法,是另外寫一個 ASP 網頁,直接將對應的 Server 端程式碼 include 近來,並立刻呼叫在此程式碼中所定義的函數,以確認無誤。以上例而言,我們所用的除錯網頁呈現效果如下:

其原始檔案 (tshowTime.asp) 如下:

<!--#INCLUDE file="showTimeServer.asp"-->

<html>
<body>

<SCRIPT RUNAT=SERVER Language=javascript>
serverTime = getTime();
Response.Write("serverTime =" + serverTime + "<br>");
</SCRIPT>

</body>
</html>

從上述範例中,我們可發覺在 client.htm 的 getTime() 函數和在 server.asp 的 getTime() 函數是一模一樣的,換句話說,我們可以只用一個包含 getTime() 的檔案,就可以達到在用戶端和伺服器端共用程式碼的效果,這是使用 JavaScript/JScript 的另一項優點。(提醒:在用戶端要使用一個包含 JavaScript 的檔案,可用 client-side include;而在伺服器端要使用一個包含 JScript 的檔案,可用 server-side include。)

有關於 RS 所提供的物件、方法和性質,可見此範例:

其原始檔案 (msRsExample.asp) 如下:

<%title="Remote Scripting 的性質和方法"%>
<!--#include file="../head.inc"-->
<hr>

<script language="JavaScript" src="_ScriptLibrary/RS.HTM"></script>
<script language="JavaScript">RSEnableRemoteScripting("_ScriptLibrary");</script>

下列按鈕可啟動 Remote Scripting:
<center>
<form>
<br><input type=button value="RSExecute Method1" onclick="handleRSExecute()" style="width:250;height:25">
<br><input type=button value="RSExecute Method1 (async)" onclick="handleRSExecuteAsync()" style="width:250;height:25">
<br><input type=button value="aspObject = RSGetASPObject" onclick="handleRSGetAspObject()" style="width:250;height:25">
<br><input type=button value="aspObject.Method2 (async)" onclick="handleAspObject()" style="width:250;height:25">
<br><input type=button value="呼叫不合格的方法所產生的回傳訊息" onclick="handleInvalidCall()" style="width:250;height:25">
</form>
</center>

原始碼:
<ul>
<li><a href="/jang/books/webprog/common/showcode.asp?source=/jang/books/webprog/06asp/example/rs/msRsExample.asp">顯示 Client 端網頁:msRsExample.asp</a>
<li><a href="/jang/books/webprog/common/showcode.asp?source=/jang/books/webprog/06asp/example/rs/msRsExampleServer.asp">顯示 Server 端網頁:msRsExampleServer.asp</a>
</ul>

<SCRIPT LANGUAGE="javascript">
var serverURL = "msRsExampleServer.asp";
var aspObject = RSGetASPObject(serverURL);

function listProp(co) {
	alert("Properties of the returned object:\n\n" +
		"status = " + co.status + "\n\n" +
		"message = " + co.message + "\n\n" +
		"context = " + co.context + "\n\n" +
		"data = " + co.data + "\n\n" +
		"return_value = " + co.return_value);
} 

function handleRSExecute() {
	var co = RSExecute(serverURL, "Method2");
	listProp(co);	
}

function errorCallBack(co) {
	alert("ERROR_CALLBACK\n\n" +
		"status = " + co.status + "\n\n" +
		"message = " + co.message + "\n\n" +
		"context = " + co.context + "\n\n" +
		"data = " + co.data);
}

function handleRSExecuteAsync() {
	RSExecute(serverURL, "Method1", listProp, "這是我自訂的訊息!");
}

function handleRSGetAspObject() {	
	var msg = "aspObject public_description\n";
	for (name in aspObject)
		msg += "   " + name + "\n";
	alert(msg);
}

function handleAspObject() {
	aspObject.Method2(listProp, errorCallBack, "aspObject");
}

function handleInvalidCall() {
	var co =  RSExecute(serverURL, "Method3", listProp, errorCallBack, "這是我自訂的錯誤訊息!");
}
</SCRIPT>

<hr>
<!--#include file="../foot.inc"-->
上述範例所用的各種物件、方法和性質,可有此微軟網頁查到。

RS 的安全層級是和 Java applet 和 IFrame 一致的。由於伺服器安全性的考量,RS 有下列限制:

範例整理

參考資料


回到「第 6 章:ASP