16-2 Session ?拐辣

Application 物件可讓同一個 Web 應用程式共用資訊,而 Session 物件可讓同一個使用者在不同的 Web 應用程式中共用資訊。換句話說,同一個使用者在不同的 Request 中,可用 Session 物件來保存資訊,而其保存資訊的方法,則是靠 Cookies 來達成。因此,要能夠使用 Session 物件的首要條件,就是用戶端的 Cookies 功能必須是開啟的。

Session 物件提供四種性質(Properties)、一種方法(Method)、兩個事件(Events)與兩個集合(Collections),列表如下:

Session 物件的性質
性質說明
CodePage語言識別碼(例:950代表繁體中文、936代表簡體中文、65001代表UTF-8)
LCID地區識別碼(例:1028代表台灣地區、3076代表香港地區、2052代表大陸地區)
SessionID用戶端的 SessionID
TimeoutSession 物件的有效時間(以分鐘為單位),預設為20分鐘

Session 物件提供的方法
方法說明
Abandon刪除 Session 物件所含的所有資訊
Contents.Remove(item or index)刪除 Contents 集合中的某一個項目
Contents.RemoveAll刪除 Contents 集合中的所有項目

Session 物件提供的事件
事件說明
OnStart啟動一個 Session 物件時所觸發的函式,此函式必須放在 global.asa 檔案
OnEnd結束一個 Session 物件時所觸發的函式,此函式必須放在 global.asa 檔案

Session 物件提供的集合
集合說明
Contents所有加在 Session 物件的變數集合
StaticObjects所有在使用者層級(Session Scope)所宣告的物件集合

當使用者點選某一個網頁時,伺服器就會對此使用者分配一個 session ID,並以 cookie 的方式記錄在用戶端。此 session ID 的有效期間是 20 分鐘,這些資訊都可由下列網頁來呈現:

Example(session/sessionId01.asp):

在上述範例中,Session.CodePage=950代表用戶端的預設語言是繁體中文(大五碼),Session.LCID=1028代表用戶端所在的區域是台灣地區,此範例的原始檔如下:

原始檔(session/sessionId01.asp):(灰色區域按兩下即可拷貝)
<%@language=JScript%>
<%title="顯示 Session.SessionID 及 Session.Timeout "%>
<!--#include file="../head.inc"-->
<hr>

<p>
Your session ID is <b><font color=green><%=Session.SessionID%></font></b>, which will be changed in
<b><font color=green><%=Session.Timeout%></font></b> minutes when you access this page again.
<p>
All session info:
	<ul>
	<li>Session.SessionID = <font color=green><%=Session.SessionID%></font>
	<li>Session.Timeout = <font color=green><%=Session.Timeout%></font>
	<li>Session.CodePage = <font color=green><%=Session.CodePage%></font>
	<li>Session.LCID = <font color=green><%=Session.LCID%></font>
	</ul>
<hr>
<!--#include file="../foot.inc"-->

由於 Session 物件是用來指定每一個使用者的相關資訊,因此我們可以根據使用者的語言或地區的不同,來顯示不同的資訊。例如 Session.LCID 是用來指定區域代碼,根據不同的區域代碼,我們就可以產生不同的日期字串,範例如下:

Example(session/sessionLcid01.asp):

上述範例的原始檔如下:

原始檔(session/sessionLcid01.asp):(灰色區域按兩下即可拷貝)
<%@language=JScript%>
<%title="經由改變 Session.LCID 來改變日期格式"%>
<!--#include file="../head.inc"-->
<hr>

<%
today=new Date();
currentLcid=Session.LCID;	// 記錄目前的 LCID
Session.LCID=1028;
Response.write("台灣:LCID="+Session.LCID + ", 當地日期字串="+today.toLocaleString());
Session.LCID=1041;
Response.write("<br>日本:LCID="+Session.LCID + ", 當地日期字串="+today.toLocaleString());
Session.LCID=1036;
Response.write("<br>法國:LCID="+Session.LCID + ", 當地日期字串="+today.toLocaleString());
Session.LCID=1031;
Response.write("<br>德國:LCID="+Session.LCID + ", 當地日期字串="+today.toLocaleString());
Session.LCID=2057;
Response.write("<br>英國:LCID="+Session.LCID + ", 當地日期字串="+today.toLocaleString());
Session.LCID=currentLcid;	// 改回原來的 LCID
%>

<hr>
<!--#include file="../foot.inc"-->

Hint
在上述範例中,你必須將 Session.LCID 設定回原來的預設值,否則與地區相關的顯示(如日期等)就會發生錯誤。

Session 和 Application 物件一樣,都有 OnStart 和 OnEnd 兩個事件,這兩個事件對應的函式是 Session_OnStart() 和 Session_OnEnd(),也都必須存放在 global.asa 檔案中。若 Application 和 Session 同時啟動,ASP 會先執行 Application_OnStart(),再執行 Session_OnStart()。若兩者同時結束,ASP 會先執行 Session_OnEnd(),再執行 Application_OnEnd()。這些執行順序可列出如下:

  1. Application_OnStart()
  2. Session_OnStart()
  3. ASP scripts
  4. Session_OnEnd()
  5. Application_OnEnd()

以下我們將使用「加強版的訪客計數器」,來說明如何使用 Session 及 Application 物件,使得用戶端在點選「重新整理」時,計數器的值不會一再累加。

其方法可說明如下:在被計數的網頁 ASP 程式碼中,檢查 Session("PreviouslyOnLine") 的值,若是 true,則不做任何事。若是 false,則將其值改為 true,並將 Application("Counter") 的值加一。換句話說,只要每次有人瀏覽此網頁,而且 Session("PreviouslyOnLine") 的值是 false,Application("Counter") 的值就會加一,其值即代表此網頁被點選的次數,它並不會因為使用者在短期(20分鐘)內點選「重新整理」而盲目增加。請見以下範例:

Example(session/pagehit01.asp):

上述範例的原始檔如下:

原始檔(session/pagehit01.asp):(灰色區域按兩下即可拷貝)
<%@language=JScript%>
<%title="使用 Application 與 Session 物件來防止計數資料的竄改:方法一"%>
<!--#include file="../head.inc"-->
<hr>

<%
if (Application("Counter")==null)
	Application("Counter") = 0;	//在 JScript,預設值不是 0
if (Session("PreviouslyOnLine")!=true){
	Application("Counter")++;
	Session("PreviouslyOnLine") = true;
}
%>
<h3 align=center>您是第 <font color=red><%=Application("Counter")%></font> 位貴賓!</h3>

<hr>
<!--#include file="../foot.inc"-->

此外,我們可以再加上「獨立計數」、「計數器啟用時間」等功能,得到一個較完整的範例:

Example(session/pagehit02.asp):

上述範例的原始檔如下:

原始檔(session/pagehit02.asp):(灰色區域按兩下即可拷貝)
<%@language=JScript%>
<%title="使用 Application 與 Session 物件來防止計數資料的竄改:方法二"%>
<!--#include file="../head.inc"-->
<hr>

<%
//Application.Contents.Removeall();	// 清除變數以便測試此網頁
//Session.Contents.Removeall();		// 清除變數以便測試此網頁
url = Request.ServerVariables("URL");
startTime = "Start time of "+url;
if (Application(startTime)==null){	// 啟始變數及時間
	Application(url)=0;		// 開始計數
	now = new Date();
	Application(startTime)=now.toLocaleString();
}
if (Session(url)==null){	// Session(url) 不存在
	Application(url)++;
	Session(url)=true;
} else {%>
	<script>alert("你想竄改計數器?沒那麼容易喔!");</script>
<%}%>
<h3 align=center>從 <font color=green><%=Application(startTime)%></font> 以來,您是第 <font color=red><%=Application(url)%></font> 位貴賓!</h3>

<hr>
<!--#include file="../foot.inc"-->

上述記數器範例雖然有許多功能,但仍有一個缺點:伺服器重開機時,Application 物件會被清除,因此所有的計數資料就不見了,一切歸零。要解決這個問題,則要將計數資料寫入檔案,後面再詳細介紹。

我們也可以每隔一天,就將記數器的資料寫入檔案,這樣的好處是:

範例如下:

Example(session/pagehit03.asp):

上述範例的原始檔如下:

原始檔(session/pagehit03.asp):(灰色區域按兩下即可拷貝)
<%@language=JScript%>
<%title="記錄每日來訪人數"%>
<!--#include file="../head.inc"-->
<hr>

<%
// 下列程式碼可以將每天訪客的人數(含頁次和人次)記錄於 counter.txt
// Application.Contents.RemoveAll();		// 清除變數以便測試此網頁
// Session.Contents.RemoveAll();		// 清除變數以便測試此網頁
if (Application("counterDate")==null){
	Application("counter1") = 0;
	Application("counter2") = 0;
	today=new Date();
	Application("counterDate") = today.getDate();
	Application("lastRecordTime") = today.toLocaleString();
}

Application("counter1")++;		// 更新頁次計數
if (Session("onlineAlready")!=true){
	Application("counter2")++;	// 更新人次計數
	Session("onlineAlready") = true;
}

// Write to a file if necessary
fso = new ActiveXObject("Scripting.FileSystemObject");
today=new Date();
counterFile="counter.txt";
if (today.getDate()!=Application("counterDate")){		// 若不在同一天,則將資料寫入檔案
	fid = fso.OpenTextFile(Server.MapPath(counterFile), 8, true);	// 8 代表附加資料於檔案,true 代表若無檔案則新增
	fid.WriteLine(today.toLocaleString());
	fid.WriteLine("頁次:"+Application("counter1"));
	fid.WriteLine("人次:"+Application("counter2"));
	fid.Close();
	Application("counter1")=0;
	Application("counter2")=0;
	Application("counterDate")=today.getDate();;
	Application("lastRecordTime")=today.toLocaleString();
}
%>

<h3 align=center>從 <font color=green><%=Application("lastRecordTime")%></font> 以來,
本頁被造訪 <font color=red><%=Application("counter1")%></font> 次,
而您是第 <font color=red><%=Application("counter2")%></font> 位貴賓!</h3>

<hr>
<!--#include file="../foot.inc"-->

而本範例所用來儲存計數資料的檔案可列出如下:

2004年12月31日 下午 09:57:26 頁次:1 人次:1 2004年12月31日 下午 09:57:27 頁次:1 人次:12005年1月1日 上午 12:22:36 頁次:18 人次:1 2005年11月21日 上午 07:42:34 頁次:1 人次:0 2006年11月22日 上午 09:07:44 頁次:1 人次:0 2015年10月1日 下午 01:14:54 頁次:2 人次:2 2015年10月5日 上午 05:14:23 頁次:4 人次:4 2015年10月17日 上午 08:08:32 頁次:2 人次:2 2015年11月11日 上午 05:53:26 頁次:2 人次:2 2015年11月18日 上午 11:01:01 頁次:2 人次:2 2015年11月29日 上午 02:57:27 頁次:2 人次:2 2015年12月29日 上午 11:15:39 頁次:2 人次:2 2016年1月16日 上午 11:48:20 頁次:2 人次:2 2016年1月18日 下午 09:44:04 頁次:2 人次:2 2016年1月23日 上午 03:10:54 頁次:2 人次:2 2016年2月2日 上午 09:54:42 頁次:3 人次:3 2016年2月18日 上午 07:50:32 頁次:2 人次:2 2016年2月21日 上午 07:26:26 頁次:2 人次:2 2016年3月1日 上午 08:27:17 頁次:2 人次:2 2016年3月5日 上午 01:09:48 頁次:2 人次:2 2016年3月11日 上午 07:53:02 頁次:2 人次:2 2016年3月18日 上午 08:11:12 頁次:2 人次:2 2016年3月22日 上午 01:31:22 頁次:3 人次:3 2016年3月31日 上午 03:39:17 頁次:2 人次:2 2016年4月10日 上午 07:15:25 頁次:2 人次:2 2016年4月15日 上午 02:25:33 頁次:2 人次:2 2016年4月21日 上午 04:40:45 頁次:4 人次:4 2016年4月22日 上午 04:07:27 頁次:23 人次:5 2016年4月28日 上午 01:39:50 頁次:2 人次:2 2016年4月29日 下午 12:43:57 頁次:2 人次:2 2016年5月3日 上午 08:35:49 頁次:3 人次:3 2016年5月11日 上午 03:44:09 頁次:5 人次:5 2016年6月24日 下午 04:51:50 頁次:3 人次:3 2016年6月30日 下午 03:22:51 頁次:4 人次:4 2016年7月3日 上午 05:19:38 頁次:2 人次:2 2016年7月11日 上午 12:55:38 頁次:2 人次:2 2016年7月29日 下午 04:02:53 頁次:2 人次:2 2016年8月4日 下午 03:34:36 頁次:2 人次:2 2016年8月12日 上午 07:23:52 頁次:4 人次:4 2016年8月19日 上午 10:19:38 頁次:2 人次:2 2016年9月1日 下午 03:34:35 頁次:2 人次:2 2016年9月6日 上午 11:45:39 頁次:4 人次:4 2016年10月8日 上午 01:14:55 頁次:3 人次:3 2016年10月17日 下午 03:57:20 頁次:2 人次:2 2016年10月19日 上午 03:27:02 頁次:3 人次:3 2016年10月21日 上午 05:05:00 頁次:2 人次:2 2016年10月23日 上午 12:08:06 頁次:2 人次:2 2016年10月26日 上午 12:02:11 頁次:2 人次:2 2016年11月2日 上午 07:01:25 頁次:2 人次:2 2016年11月3日 上午 09:20:12 頁次:2 人次:2 2016年11月9日 下午 01:23:28 頁次:2 人次:2 2016年11月13日 上午 01:10:09 頁次:3 人次:3 2016年11月14日 上午 06:57:01 頁次:3 人次:3 2016年11月17日 上午 09:33:33 頁次:4 人次:4 2016年11月19日 下午 12:46:56 頁次:2 人次:2 2016年11月25日 下午 01:29:34 頁次:2 人次:2 2016年11月26日 上午 10:13:15 頁次:2 人次:2 2016年12月17日 上午 02:16:57 頁次:5 人次:5 2016年12月18日 上午 01:48:56 頁次:2 人次:2 2016年12月25日 上午 09:56:23 頁次:2 人次:2 2017年1月5日 上午 01:46:50 頁次:2 人次:2 2017年1月10日 上午 02:42:13 頁次:2 人次:2 2017年1月28日 上午 07:11:23 頁次:2 人次:2 2017年2月9日 上午 01:15:41 頁次:2 人次:2 2017年2月15日 上午 12:39:26 頁次:2 人次:2 2017年2月16日 下午 06:00:07 頁次:2 人次:2 2017年2月18日 上午 05:06:28 頁次:3 人次:3 2017年2月22日 上午 04:55:06 頁次:2 人次:2 2017年2月26日 上午 12:22:30 頁次:2 人次:2 2017年3月3日 下午 12:11:06 頁次:2 人次:2 2017年3月9日 下午 12:10:52 頁次:4 人次:4 2017年3月14日 上午 02:52:21 頁次:2 人次:2 2017年3月15日 上午 07:43:01 頁次:2 人次:2 2017年3月30日 上午 01:53:50 頁次:2 人次:2 2017年4月5日 上午 05:51:12 頁次:3 人次:3 2017年4月9日 上午 04:45:52 頁次:2 人次:2 2017年4月10日 上午 12:34:57 頁次:1 人次:1 2017年4月12日 上午 07:20:20 頁次:3 人次:2 2017年4月16日 上午 10:14:37 頁次:2 人次:2 2017年4月19日 上午 03:45:17 頁次:2 人次:2 2017年4月22日 上午 05:49:32 頁次:2 人次:2 2017年4月25日 上午 03:53:28 頁次:2 人次:2 2017年5月1日 上午 01:31:23 頁次:2 人次:2 2017年5月6日 上午 12:32:43 頁次:2 人次:2 2017年5月10日 上午 02:29:47 頁次:2 人次:2 2017年5月11日 上午 02:05:07 頁次:2 人次:2 2017年5月13日 上午 01:13:06 頁次:2 人次:2 2017年5月18日 上午 01:33:11 頁次:3 人次:3 2017年5月19日 上午 10:09:46 頁次:4 人次:4 2017年5月23日 上午 05:01:31 頁次:2 人次:2 2017年5月25日 上午 01:08:49 頁次:4 人次:4 2017年6月6日 上午 01:43:11 頁次:3 人次:3 2017年6月7日 上午 10:21:56 頁次:2 人次:2 2017年6月8日 上午 03:51:46 頁次:4 人次:4 2017年6月13日 上午 12:02:38 頁次:2 人次:2 2017年6月21日 上午 02:05:22 頁次:4 人次:4 2017年6月24日 上午 01:07:01 頁次:2 人次:2 在上述範例中,我們將計數資料分為「頁次」和「人次」:

Session 物件是一個很好用的保存資訊方法,其他相關應用有:

特別必須注意的是:Session 物件的正常運作必須倚賴用戶端開啟 Cookies 功能,因此如果妳的網頁使用到 Session 物件,最好必須在網頁之前加上測試 Cookies 是否開啟的測試,若未開啟,可提醒使用者開啟 Cookies 以確保網頁正常運作。

Hint
事實上,用戶端的 Cookies 只是用來存放 session ID,而其他與 session 相關的資訊都存放在伺服器,但伺服器必須靠 session ID 才能取得這些資訊。


JScript 程式設計與應用:用於伺服器端的 ASP 環境