.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號:N120812702
出刊日期:2012/08/15
在設計網頁時,若要想要用戶端儲存一些資料,通常會使用Cookie物件來解決,這樣可以不用浪費伺服端的資源,也不用花費力氣在發出HTTP請求時,還得將Cookie送到伺服端。在HTML 5 之後,您有了新的選擇,可以在用戶端瀏覽器所在的電腦上儲存一些資料,這資料不會隨著HTTP請求送到伺服端。本文將介紹如何在網頁中使用Cookie與HTML 5 Web Storage API來儲存資料。
使用Cookie儲存用戶端資料
Cookie是常被網頁程式用來在瀏覽器所在的電腦上保存資料的一種方式,不過使用cookie時有一些限制,例如cookie資料量最多只能夠儲存4KB,它可能儲存在瀏覽器的記憶體,或者是以文字檔的形式儲存在用戶端的電腦中。且每回發送HTTP請求到伺服器時,需要將cookie的資料傳送到伺服端。
Cookie有逾期時間,我們可以在Web伺服器或瀏覽器中利用程式碼來設定逾期時間,超過逾期時間後,Cookie就視為無效,若沒有為Cookie設定逾期時間,此Cookie就稱為暫時的Cookie,當瀏覽器關閉時,便消失;若設定了逾期時間,此Cookie就會以文字檔的型式,儲存用戶端電腦上。
參考以下設定以及讀取Cookie的範例程式碼,SaveData方法用來儲存cookie;ReadData方法用來讀取cookie:
<!DOCTYPE html>
<html xmlns = "
http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
var expire = new Date();
expire.setDate( expire.getDate() + 10 );
var mycookie = text1.value + "; expires=" + expire.toUTCString();
document.cookie= "cookieName=" + mycookie;
}
function ReadData() {
var div1 = document.getElementById("result");
div1.textContent = document.cookie;
}
function contentLoaded() {
document.getElementById('Button1').addEventListener( 'click', SaveData, false );
document.getElementById('Button2').addEventListener( 'click', ReadData, false );
}
window.addEventListener("DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<input id = "Text1" type = "text" />
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
</body>
</html>
在SaveData方法中,範例建立一個Date型別物件,並叫用setDate方法,將逾時時間設定為目前時間往後10天。接著將cookie的資訊設定到document.cookie,語法是「cookieName=」字串串接cookie值,加上「;」號,再串接逾期時間。
在ReadData方法中我們可以直接使用document.cookie的語法來讀出cookie的值顯示在畫面上。
注意:若使用Firefox 13瀏覽器來進行測試,可以使用file:///方式,直接開啟html檔案,就可以讀寫Cookie;但若使用Chrome瀏覽器,需要將html放到Web伺服器上以http方式來執行,這樣才可以讀寫Cookie。
最後要提醒一下,Cookie在使用上要注意它的限制,有些瀏覽器限制了一個網站最多的Cookie數量只能有20個左右;再來,使用者可能會在瀏覽器上做設定,將Cookie的功能關閉,這樣就無法存取Cookie的資訊。
Web Storage API
Web Storage是HTML 5規格中定義的新API,提供一些內建的方法可以讓用戶端儲存具有結構性的資料,並提供比Cookie更大的儲存空間(大部分的瀏覽器預設是5MB,比Cookie 4KB要大很多),以及更佳的程式化介面來讓你操作資料。
Web Storage API主要提供兩個JavaScript物件來存取資料:sessionStorage物件與localStorage物件,這兩個物件都是屬於字典類型的物件,可以儲存key與value配對的資料。value則是字串型別,也可以是一個以字串表示的JSON物件。
localStorage物件可以在用戶端與伺服端之間的工作階段(Session)結束時,繼續存取資料,即使關閉瀏覽器,資料還是存在。同時在不同的瀏覽器視窗,或一個瀏覽器視窗中不同的頁籤(Tab),都可以共用這些資料。
sessionStorage的生命周期限定在一個視窗(Window),當瀏覽器視窗關閉時就會不見,也不能跨一個視窗中的不同頁籤(Tab)來存取。
測試瀏覽器是否支援Web Storage
目前大部分的瀏覽器都已經支援Web Storage API,若要了解目前使用的Firebox、Chrome或ie瀏覽器是否已支援此API,可以試試看在瀏覽器的控制台(Console)下一個測試指令「’localStorage’ in window」,若回傳true就代表有支援localStorage,同樣也可以下「'sessionStorage' in window」指令來判斷是否支援sessionStorage,請參考圖1所示,此為使用Firebox瀏覽器網頁主控台測試的結果:

圖 1:使用Firefox測試瀏覽器是否支援localStorage。
請參考圖2所示,此為使用Chrome瀏覽器console測試的結果:

圖 2:使用Chrome測試瀏覽器是否支援localStorage。
圖3則是使用ie8瀏覽器console測試的結果:

圖 3:使用ie8測試瀏覽器是否支援localStorage。
使用JavaScript測試是否支援Web Storage
若想要在用戶端使用JavaScript程式碼來測試瀏覽器是否支援Web Storage的功能,可以撰寫如下的supportWebStorage方法:
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function supportWebStorage () {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch ( e ) {
return false;
}
}
function contentLoaded () {
if ( supportWebStorage() )
alert('support!!');
else
alert('Not support!!');
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
</body>
</html>
若supportWebStorage方法回傳true,便代表瀏覽器有提供支援,若為false便表示不支援。當你在瀏覽器開啟此網頁,就會跳出一個訊息方塊,顯示偵測的結果。
另一個測試的方式是採用Modernizr,要使用之前需要先到http://modernizr.com/網站下載http://modernizr.com/downloads/modernizr-2.5.3.js檔案(這為目前最新版本),然後在網頁中使用它來進行判斷。如果不想要下載這些js檔案到網站之中使用,有個更簡便的引用方式,你可以直接從微軟的Microsoft Ajax Content Delivery Network 引用Modernizr Releases on the CDN 來判斷即可,網址在:http://www.asp.net/ajaxlibrary/cdn.ashx。參考以下範例,引用微軟Microsoft Ajax Content Delivery Network,並在網頁載入時,利用Modernizr.localstorage來判斷瀏覽器是否支援localStorage:
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" src = "http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.0.6-development-only.js" > </script>
<script type = "text/javascript" >
function contentLoaded () {
if ( Modernizr.localstorage )
alert('support!!');
else
alert('Not support!!');
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
</body>
</html>
在瀏覽器使用local Storage
若瀏覽器支援了Web Storage,您可以利用瀏覽器的Console來存取其中的值。我們可以使用類似屬性語法存取資料,以下透過Chrome瀏覽器的Console來示範如何讀寫資料到localStorage,舉例來說,若想要在localStorage新增一個name,來儲存「mytest」這個值,可以在Console中直接撰寫以下指令:
localStorage.name=”mytest”
要讀取name的值,可以直接下指令:
localStorage.name
若要刪除name,可以使用delete語法:
Delete localStorage.name
請參考圖4為此範例執行的結果:

圖 4:使用屬性的語法來讀寫localStorage。
除了使用類似屬性的語法來讀寫資料之外,還可以透過localStorage物件提供的setItem、getItem方法來寫入或讀取資料。例如以下的範例以Chrome瀏覽器做測試,請參考圖5所示:

圖 5:使用localStorage物件的setItem、getItem方法來寫入或讀取資料。
local Storage的setItem方法用來設定資料,範例中傳入key值為「data」;值為「123」。local Storage的getItem方法用來讀取資料,範例中傳入「data」當key值,取得對應的「123」。
length attribute用來取得local Storage中資料的數量。而Clear方法則用來清除local Storage中所有的資料。若沒有叫用Clear方法清除local Storage中所有的資料,而將瀏覽器關閉,再重新開啟瀏覽器,您還是可以讀取到key值為「data」的「123」值,這表示local Storage是可以跨瀏覽器來讀取的,不會因為瀏覽器關閉而讓資料消失不見。
在瀏覽器使用session Storage
session Storage不能跨視窗,也不能跨Tab(頁籤來存取),例如以下以Chrome瀏覽器為範例,在第一個頁籤(Tab)中,利用Console叫用sessionStorage物件的setItem方法,設定key為「aaa」,對應的值為「bbb」,並利用getItem方法將值取出,請參考圖6所示:

圖 6:使用Chrome瀏覽器讀寫session Storage。
而在同一個瀏覽器的另一個Tab(頁籤),是無法讀取到這個值,請參考圖7所示:

圖 7:session Storage不能跨不同頁籤來存取。
同樣的,當你開啟新的瀏覽器視窗,也是無法取得這個值。
在網頁中使用Local Storage
在用戶端的javaScript程式碼中可以直接使用Local Storage,例如以下使用localStorage物件的讀寫範例,範例中立用localStorage的getItem與setItem方法來讀寫資料。
<!DOCTYPE html>
<html xmlns = "
http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
localStorage.setItem( "mydata", text1.value );
}
function ReadData() {
var div1 = document.getElementById("result");
div1.textContent = localStorage.getItem( "mydata" );
}
function contentLoaded () {
document.getElementById('Button1').addEventListener('click', SaveData, false);
document.getElementById('Button2').addEventListener( 'click', ReadData, false );
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<input id = "Text1" type = "text" />
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
</body>
</html>
在網頁中使用sessionStorage
在網頁中使用sessionStorage的方式和使用localStorage非常類似,例如以下改寫上個範例,只把localStorage改為sessionStorage:
<!DOCTYPE html>
<html xmlns = "
http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
sessionStorage.setItem( "mydata", text1.value );
}
function ReadData () {
var div1 = document.getElementById("result");
div1.textContent = sessionStorage.getItem( "mydata" );
}
function contentLoaded () {
document.getElementById('Button1').addEventListener( 'click', SaveData, false );
document.getElementById('Button2').addEventListener( 'click', ReadData, false );
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<input id = "Text1" type = "text" />
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
</body>
</html>
使用索引
除了使用getItem與setItem方法來讀寫資料之外,你也可以利用索引的語法來讀取,例如以下範例程式,以key值當索引來存取sessionStorage:
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
sessionStorage["mydata"] = text1.value;
}
function ReadData () {
var div1 = document.getElementById("result");
div1.textContent = sessionStorage["mydata"];
}
function contentLoaded () {
document.getElementById('Button1').addEventListener( 'click', SaveData, false );
document.getElementById('Button2').addEventListener( 'click', ReadData, false );
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<input id = "Text1" type = "text" />
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
</body>
</html>
列出所有資料
不管是localStorage或sessionStorage都可以存放多個資料,例如以下範例程式,在Save方法中儲存兩個值,在ReadData方法中,利用sessionStorage.length取得要執行的迴圈個數,再叫用sessionStorage.key方法取得key值,然後以key值來取得value:
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
var text2 = document.getElementById("Text2");
sessionStorage["mydata"] = text1.value;
sessionStorage["mydata2"] = text2.value;
}
function ReadData() {
var div1 = document.getElementById("result");
for( var i=0; i< sessionStorage.length; i++ ) {
var key = sessionStorage.key(i);
var value = sessionStorage[key];
div1.textContent += key +" => " + sessionStorage[key] + ";" ;
}
}
function contentLoaded () {
document.getElementById('Button1').addEventListener( 'click', SaveData, false );
document.getElementById('Button2').addEventListener( 'click', ReadData, false );
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<input id = "Text1" type = "text" />
<input id = "Text2" type = "text" />
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
</body>
</html>
範例執行結果如圖8所示,在兩個文字方塊中分別輸入「123」與「456」,然後儲存,接著再讀取出來顯示。

圖 8:列出所有資料。
儲存物件或陣列資料
若要在Web Storage之中儲存物件或陣列的資料,則需要使用JSON的stringify方法,將其轉換成JavaScript Object Notation (JSON) 字串;然後利用JSON.parse 方法將JavaScript Object Notation (JSON)字串還原成物件或陣列。例如以下範例程式碼:
<!DOCTYPE html>
<html xmlns = "
http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
var empList= ['Mary', 'Candy', 'July'] ;
localStorage.employees = JSON.stringify( empList );
}
function ReadData() {
var div1 = document.getElementById("result");
var empList = JSON.parse( localStorage.employees );
div1.textContent = '共' + empList.length + '筆 : ' + empList[0] + ',' + empList[1] + ',' + empList[2] ;
}
function contentLoaded () {
document.getElementById('Button1').addEventListener( 'click', SaveData, false );
document.getElementById('Button2').addEventListener( 'click', ReadData, false );
}
window.addEventListener ("DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
</body>
</html>
在ReadData方法中宣告一個empList陣列,初始化為三個元素:「Mary」、「Candy」與「July」,利用JSON的stringify方法轉換成JSON字串後,便可以直接存放到localStorage。而在ReadData方法中利用JSON.parse方法,將字串還原成一個陣列,從length屬性便可取得其中的項目有三個,然後利用索引便可取得陣列中的值。
移除資料
若要清除資料,可以使用Clear方法,或是removeItem方法。Clear 方法會清除所有資料;而removeItem方法可以移除特定key值的資料;底下的範例程式碼在RemoveData方法中,利用sessionStorage物件的removeItem方法移除key值為「mydata」的資料;在RemoveAllData方法中,利用sessionStorage物件的clear方法移除所有資料。
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
var text2 = document.getElementById("Text2");
sessionStorage["mydata"] = text1.value;
sessionStorage["mydata2"] = text2.value;
}
function ReadData() {
var div1 = document.getElementById("result");
div1.textContent="";
for( var i=0; i< sessionStorage.length; i++ ) {
var key = sessionStorage.key(i);
var value = sessionStorage[key];
div1.textContent += key +" => " + sessionStorage[key] + ";" ;
}
}
function RemoveData() {
sessionStorage.removeItem("mydata");
}
function RemoveAllData() {
sessionStorage.clear();
}
function contentLoaded() {
document.getElementById('Button1').addEventListener( 'click', SaveData, false );
document.getElementById('Button2').addEventListener( 'click', ReadData, false );
document.getElementById('Button3').addEventListener( 'click', RemoveData, false );
document.getElementById('Button4').addEventListener( 'click', RemoveAllData, false );
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<input id = "Text1" type = "text" />
<input id = "Text2" type = "text" />
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
<input id = "Button3" type = "button" value = "Remove" />
<input id = "Button4" type = "button" value = "RemoveAll" />
</body>
</html>
Web Storage事件
Web Storage API包含一個storage事件,在你叫用setItem、removeItem或clear方法變更包含在Web Storage中的值時觸發此事件,所有其它開啟相同網頁的視窗,或Tab都會收到此事件,但進行異動作業的widow則不會觸發此事件。若某個key對應的value沒有變動時,也不觸發。我們可以利用storage事件來追蹤異動。參考範例如下,網頁載入時,利用window.addEventListener來註冊並攔截storage事件 (提示,ie9版本之後才支援window.addEventListener方法,若為ie8需改用window.attachEvent方法來註冊事件):
<!DOCTYPE html>
<html xmlns = "http://www.w3.org/1999/xhtml" >
<head>
<title> </title>
<script type = "text/javascript" >
function SaveData () {
var text1 = document.getElementById("Text1");
localStorage.setItem( "mydata", text1.value );
}
function ReadData( e ) {
var div1 = document.getElementById("result");
div1.textContent = '';
for( var i=0; i< localStorage.length; i++ ) {
var key = localStorage.key(i);
var value = localStorage[key];
div1.textContent += key +" => " + localStorage[key] + ";" ;
}
}
function storageChange( e ) {
alert("storageChange");
var div1 = document.getElementById("result");
alert( "key=" + e.key + "; old value = " + e.oldValue + "; new value = " + e.newValue);
}
function contentLoaded () {
document.getElementById('Button1').addEventListener( 'click', SaveData, false);
document.getElementById('Button2').addEventListener( 'click', ReadData, false);
window.addEventListener( "storage", storageChange , false );
}
window.addEventListener( "DOMContentLoaded", contentLoaded, false );
</script>
</head>
<body>
<input id = "Text1" type = "text" />
<div id = "result"> </div>
<input id = "Button1" type = "button" value = "Save" />
<input id = "Button2" type = "button" value = "Read" />
</body>
</html>
以下是以Firefox 13瀏覽器測試的結果,在瀏覽器中兩個頁籤(Tab)都執行相同的網頁,在第一個頁籤的文字方塊中輸入資料「123」後,按下「Save」按鈕,將資料寫入localStorage,再按下「Read」按鈕讀取出來,顯示在畫面上,請參考圖9所示:

圖 9:將資料寫入localStorage,再讀取出來顯示。
接下來切換到第二個頁籤,進行相同的作業,在第二個頁籤的文字方塊中輸入資料「456」後,按下「Save」按鈕,將資料寫入localStorage,此時馬上會觸發第一個頁籤的storage事件,跳出訊息。但要注意的是,並不會觸發第二個頁籤的storage事件,請參考圖10所示:

圖 10:觸發storage事件。
接著顯示出異動前與異動後的資料,請參考圖11所示:

圖 11:顯示出異動前與異動後的資料。
在storage事件觸發時,我們可以從event物件來取得許多資訊:
- key:新增的、刪除或修改過資料的key值。
- oldValue:某key值在異動前原始的值。若storage是因新增資料而觸發,則oldValue的內容會是null。
- newValue:異動後的新值。
- url:觸發事件的網頁url path。
- storageArea:storage物件。
注意:若使用Firefox 13瀏覽器來進行測試,可以使用file:///方式,直接開啟html檔案,就可以測試事件;但若使用Chrome瀏覽器,需要將html放到Web伺服器上以http方式來執行,這樣事件才會運作。
總結
大部分瀏覽器實作Web Storage的儲存空間是5MB,而Cookie是4KB。每回用戶端發送請求到伺服器都需要夾帶Cookie到伺服器,因此伺服器需要知道Cookie。Web Storage則是完全在用戶端實作,資料不用送到伺服器,伺服器不需要知道相關的資訊。Web Storage提供localStorage、sessionStorage等JavaScript物件來存取資料。Cookie則以字串方式讀取。Web Storage支援事件機制,而Cookie不支援。