แต่ก่อนเราอาจจะเคยใช้ cookie ในการจัดเก็บข้อมูลของ users แต่สำหรับ html5 แล้ว มีอีกวิธีที่น่าสนใจ นั่นก็คือการใช้ web storage
การเก็บข้อมูลไว้ที่ฝั่ง Client มันดียังไง ?
โดยทั่วไปแล้ว เว็บต่างๆ มักจะเก็บข้อมูลเอาไว้ที่ฝั่ง server แต่จริงๆ แล้ว การเก็บข้อมูลเอาไว้ที่ฝั่ง client ก็สามารถทำได้เช่นกัน และยังมีข้อดีตรงที่
- เข้าถึงข้อมูลได้ด้วย JavaScriptในบางครั้งเราต้องการนำข้อมูลไปใช้ด้วย JavaScript ซึ่งเป็นภาษาฝั่ง client ที่สามารถเข้าถึงข้อมูลที่เก็บเอาไว้ที่ฝั่ง client ได้โดยสะดวก
- ลดภาระของ Serverการเก็บข้อมูลไว้ที่ฝั่ง client เหมือนเป็นการกระจายภาระของ server ไปให้ทางฝั่ง client
เพราะ Cookie ไม่ดีพอ
หากเราต้องการจะเก็บข้อมูลเอาไว้ที่ฝั่ง client หลายๆ คนคงจะนึกถึง cookie แต่เนื่องจากมันถูกสร้างขึ้นมาเพื่อประโยชน์สำหรับภาษา script ทางฝั่ง server เป็นหลัก ทำให้มันมีข้อจำกัดดังนี้
- ช้าในทุกๆ ครั้งที่เกิด HTTP request ข้อมูล cookie จะต้องถูกส่งไปด้วย ส่งผลให้การส่งผ่านข้อมูลนั้นช้าลง
- เล็กและด้วยเหตุผลข้างต้น ขนาดของ cookie จึงถูกจำกัดไว้เพียงแค่ 4 KB เท่านั้น ซึ่งนั่นอาจไม่เพียงพอ
ด้วยข้อจำกัดดังกล่าว ใน html5 จึงได้มีการจัดเก็บข้อมูลในรูปแบบใหม่ที่เรียกว่า web storage
รู้จักกับ HTML5 Web Storage
web storage ใน html5 จะใช้สำหรับจัดเก็บข้อมูลเอาไว้ที่ฝั่ง client เหมือนๆ กับ cookie เลย เพียงแต่มันจะถูกออกแบบมาเพื่อให้ใช้กับภาษาฝั่ง client โดยเฉพาะ ทำให้มันมีข้อได้เปรียบเหนือ cookie ตรงที่
- เร็วกว่าข้อมูลจาก web storage จะไม่ถูกส่งไปพร้อมกับ HTTP request แต่จะถูกนำมาใช้ก็ต่อเมื่อมีการเรียกใช้เท่านั้น
- ใหญ่กว่าขนาดของ web storage นั้นใหญ่กว่า cookie หลายเท่า (5MB ต่อ 1 โดเมน)
การใช้ web storage ยังถูกแบ่งออกเป็น 2 แบบด้วยกัน ได้แก่ localStorage และ sessionStorage ทั้งนี้ก็เพื่อให้เหมาะสมในการใช้งานที่หลากหลาย
localStorage vs. sessionStorage
เราสามารถแบ่ง web storage ตามลักษณะการใช้งานได้เป็น 2 แบบ ด้วยกัน ดังนี้
- localStorageข้อมูลที่เก็บด้วย localStorage จะเก็บไปตลอดกาล ไม่มีวันหมดอายุ
- sessionStorageข้อมูลที่เก็บด้วย sessionStorage จะหายไปเมื่อมีการปิด window หรือ tab นั้นๆ
เราจะเห็นว่า localStorage และ sessionStorage นั้นเหมือนกันแทบทุกประการ สิ่งเดียวที่มันต่างกันก็คือ “ระยะเวลา” ที่จะเก็บข้อมูลเอาไว้นั่นเอง
วิธีใช้งาน Web Storage ขั้นพื้นฐาน
ทั้ง localStorage และ sessionStorage ต่างก็เป็น object สำหรับจัดเก็บข้อมูล และทั้งคู่ยังมี methods และ property ที่เหมือนกันทุกประการ ดังนี้
- setItem(key, value)เก็บข้อมูล
- getItem(key)ดึงข้อมูลที่เก็บไว้ออกมาใช้ ตาม key ที่ระบุ
- removeItem(key)ลบข้อมูลที่เคยเก็บไว้ ตาม key ที่ระบุ
- key(n)แสดงชื่อของ key ตาม index ที่ระบุ (เริ่มที่ 0)
- clear()ลบข้อมูลที่จัดเก็บไว้ทั้งหมด (เฉพาะโดเมนนั้นๆ)
- lengthแสดงจำนวนข้อมูลที่จัดเก็บไว้ทั้งหมด (เฉพาะโดเมนนั้นๆ)
ทีนี้เราลองมาดูตัวอย่างการใช้งาน localStorage แบบพื้นฐานกันก่อน
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /* สร้าง key ชื่อ 'textSize' เพื่อเอามาเก็บค่า 'large' */ localStorage.setItem('textSize', 'large'); /* สร้าง key ชื่อ 'view' เพื่อเอามาเก็บค่า 'list' */ localStorage.setItem('view', 'list'); /* แสดงค่าของ key ที่ชื่อ 'textSize' */ var textSize = localStorage.getItem('textSize'); console.log(textSize); /* = large */ /* แสดงชื่อของ key ตัวแรกที่ได้เก็บไว้ */ var firsKey = localStorage.key(0); console.log(firstKey); /* = textSize */ /* แสดงจำนวนข้อมูลที่จัดเก็บไว้ทั้งหมด */ var total = localStorage.length; console.log(total); /* = 2 */ /* ลบข้อมูลของ key ที่ชื่อ 'view' */ localStorage.removeItem('view'); var view = localStorage.getItem('view'); console.log(view); /* = null */ /* ลบข้อมูลทั้งหมด */ localStorage.clear(); var textSize = localStorage.getItem('textSize'); console.log(textSize); /* = null */ |
แต่หากเราต้องการจะล้างข้อมูลที่ได้เก็บไปทั้งหมดเมื่อมีการปิด window หรือ tab ก็ให้เราเปลี่ยนมาใช้ sessionStorage แทน โดยการเปลี่ยนชื่อ object จาก localStorage มาเป็น sessionStorage
Web Storage เก็บได้แต่ String !
ข้อมูลที่ต้องการจะจัดเก็บด้วย web storage จะต้องอยู่ในรูปแบบ string เท่านั้น หากเราต้องการจะจัดเก็บ object เราจะต้องแปลงมันให้เป็น string ก่อนเสมอ
1 2 3 4 5 6 7 8 9 10 | /* สร้าง object ชื่อ 'settings' */ var settings = {}; settings.textSize = 'large'; settings.view = 'list'; /* ใช้ JSON.stringify เพื่อแปลง object ให้เป็น string ก่อนที่จะเก็บ */ localStorage.setItem('settings', JSON.stringify(settings)); /* ใช้ JSON.parse เพื่อแปลง string กลับมาเป็น object ก่อนนำไปใช้ */ console.log(JSON.parse(localStorage.getItem('settings'))); |
เราสามารถนำ Web Storage ไปทำอะไรได้บ้าง ?
เราสามารถนำความสามารถของ web storage ไปประยุกต์ใช้กับ web application ได้หลายรูปแบบด้วยกัน ดังนี้
- เก็บค่า Preferencesใช้เก็บค่าต่างๆ ที่ users สามารปรับแต่งได้เอง เช่น ขนาดตัวอักษร หรือมุมมอง เป็นต้น
- เก็บสถานะการใช้งานล่าสุดใช้เพื่อเก็บรักษาสถานะของ web application หรือค่า input ต่างๆ ในฟอร์ม ให้คงอยู่เหมือนเดิมแม้ว่าจะปิด web application ไปแล้ว
- Cache ข้อมูลใช้เก็บข้อมูลบางส่วนที่ไม่ต้องการการอัพเดทแบบ real-time เพื่อจะได้ลดภาระของ server ให้น้อยลง
มาถึงตอนนี้ เรารู้แล้วว่า web storage สามารถทำอะไรได้บ้าง ทีนี้เราลองมาลงมือใช้ web storage จริงๆ กันเลยดีกว่า
Workshop – เก็บ Preferences ด้วย localStorage
สมมติว่าเว็บเรามีฟังก์ชันให้ users สามารถปรับขนาดตัวอักษรได้ด้วยตัวเอง เราไม่อยากให้ users ต้องมากำหนดใหม่ทุกครั้งที่เปลี่ยนหน้าเว็บหรือตอนเข้าเว็บใหม่ เราจึงตัดสินใจจะใช้ web storage เข้ามาช่วยเก็บ “ขนาดของตัวอักษร” ที่ users ได้เลือกไว้
ก่อนอื่นเราต้องเขียน html สำหรับส่วนของฟังก์ชันเปลี่ยนขนาดตัวอักษรและส่วนสำหรับแสดงเนื้อหาขึ้นมาก่อน โค้ด html ของเราจะได้ประมาณนี้
1 2 3 4 5 6 7 8 | <div class="panel"> <button data-font-size="0.5em">small</button> <button data-font-size="1em">medium</button> <button data-font-size="1.5em">large</button> </div> <div class="content"> จดจำขนาดของตัวอักษรที่ users ชอบด้วย localStorage </div> |
ต่อมาให้เราเขียนโค้ด javascript เพื่อใช้เปลี่ยนขนาดตัวอักษรให้เป็นไปตามที่ users เลือก และเก็บลง web storage ด้วย เพื่อที่เวลาเปลี่ยนหน้าใหม่ users จะได้ไม่ต้องมาเลือกอีก
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | jQuery(function($){ /* สร้าง function สำหรับเปลี่ยน font-size ตามตัวแปรที่รับไป */ var changeFontSize = function(size){ $('.content').css('font-size', size); } /* ตรวจสอบว่ามีข้อมูลเก็บไว้ใน localStorage แล้วหรือยัง? */ if(localStorage.getItem('fontSize') != null){ /* ถ้ามีแล้ว ให้เปลี่ยนขนาดตัวอักษร โดยใช้ค่าจาก localStorage */ changeFontSize(localStorage.getItem('fontSize')); } /* จะทำอะไร เมื่อ user กดเปลี่ยนขนาดตัวอักษร? */ $('.panel button').on('click', function(){ var size = $(this).attr('data-font-size'); /* เก็บขนาดตัวอักษรที่ user เลือก ลงใน localStorage */ localStorage.setItem('fontSize', size); /* เปลี่ยนขนาดตัวอักษร โดยใช้ค่าตามที่ user ได้เลือกมา */ changeFontSize(size); }); }); |
จะเห็นว่าในกรณีนี้เราเลือกใช้ localStorage เนื่องจากการใช้ sessionStorage จะทำให้ users ต้องมาเลือกขนาดตัวอักษรใหม่ทุกครั้งหากเค้าปิดเว็บไปแล้ว
Workshop – เก็บสถานะล่าสุดด้วย localStorage
ในบางครั้ง เราอาจต้องการอำนวยความสะดวกให้กับ users โดยการนำข้อมูลที่เค้ากรอกในฟอร์มครั้งล่าสุดมาแสดงรอไว้เลย เพื่อที่เค้าจะได้ไม่ต้องมากรอกข้อมูลใหม่หมดทุกครั้ง
สมมติเว็บเรามีฟอร์มสำหรับลงชื่อเข้าสู่ระบบ เราอาจเพิ่ม feature สำหรับจดจำข้อมูล username รวมไปถึง password เพื่อที่ users จะได้รับความสะดวกในการลงชื่อเข้าสู่ระบบมากขึ้น โค้ด html ของเราจะเป็นแบบนี้
1 2 3 4 5 6 7 8 9 10 | <form class="form-signin" method="get" action=""> <fieldset> <legend>Signin</legend> <label for="username">Username</label> <input type="text" name="username" placeholder="Username" value=""> <label for="password">Password</label> <input type="password" name="password" placeholder="Password" value=""> <button class="form-submit">Sign in</button> </fieldset> </form> |
เมื่อมีการ submit ฟอร์ม เราจะทำการบันทึกข้อมูลทั้งหมดในฟอร์มลงไปใน web storage และมีการเช็คทุกๆ ครั้งตอนโหลดหน้าเว็บ ว่าถ้าข้อมูลของฟอร์มนั้นมีอยู่ใน web storage แล้ว ให้นำข้อมูลเหล่านั้นมาแสดงในฟอร์มได้เลย โค้ด javascript ของเราจะได้ประมาณนี้
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | jQuery(function($){ /* สร้างฟังก์ชันสำหรับกรอกข้อมูลลงในฟอร์ม */ var fillForm = function(form, data){ $.each(data, function(i, field) { $(form+' input[name="'+field.name+'"]').val(field.value); }); } /* สร้างฟังก์ชันสำหรับบันทึกข้อมูลจากฟอร์มลงใน localStorage */ var saveFormData = function(form){ data = form.serializeArray(); localStorage.setItem('signinData', JSON.stringify(data)); } /* ตรวจสอบว่ามีข้อมูลเก็บไว้ใน localStorage แล้วหรือยัง? */ if(localStorage.getItem('signinData') != null){ /* ถ้ามีแล้ว ให้กรอกข้อมูลลงในฟอร์ม โดยใช้ค่าจาก localStorage */ fillForm('.form-signin', JSON.parse(localStorage.getItem('signinData'))); } /* จะทำอะไร เมื่อ user กดปุ่ม submit ฟอร์ม? */ $('.form-signin').on('submit', function(event){ /* บันทึกข้อมูลจากฟอร์มลงใน localStorage */ saveFormData($(this)); }); }); |
อย่างไรก็ตาม การเก็บข้อมูลสำคัญๆ ลงใน web storage อาจไม่ปลอดภัยเท่าไรนัก หากเราจะใช้ feature นี้กับข้อมูลที่เป็นความลับ เราจะต้องถาม users ก่อนเสมอว่าเครื่องคอมพิวเตอร์เครื่องนี้เป็นเครื่องส่วนตัวหรือไม่
Workshop – Cache ข้อมูล ด้วย localStorage
สำหรับข้อมูลที่ไม่ได้มีการอัพเดทบ่อยมากนัก เราอาจเก็บเอาไว้ที่ฝั่ง client เลยก็ได้ และพอถึงเวลาที่มีการอัพเดท เราก็ค่อยไปล้างข้อมูลที่เครื่องของ users แล้วจึงเก็บข้อมูลที่เพิ่งอัพเดทใหม่เข้าไปแทน
สมมติเว็บเรามีส่วนที่เอาไว้แสดง content จาก feed เราไม่อยากให้ส่วนนี้ต้องเชื่อมต่อไปยังฐานข้อมูลของ server ทุกครั้ง เพราะข้อมูลนั้นนานๆ จะอัพเดทซะที เราจึงใช้วิธีเก็บ content จาก feed ลงใน web storage แล้วอ่าน content จากในนั้นแทน
โค้ด html ของส่วนแสดง content จาก feed จะเป็นแบบนี้
1 | <div class="content"></div> |
จากนั้นเราจะต้องเขียนโค้ด javascript เพื่อตรวจดูว่าใน web storage มี content จาก feed เก็บเอาไว้แล้วหรือยัง ถ้ามีแล้ว ให้นำมาแสดงได้เลย แต่ถ้ายังไม่มี ให้ไปเอา content มาจาก feed เสียก่อน แล้วจึงเก็บ content เหล่านั้นลง web storage คราวหน้าเราจะได้ไม่ต้องไปอ่านจาก feed อีก
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | jQuery(function($){ /* สร้างฟังก์ชันสำหรับแสดง content จาก feed */ var showFeed = function(feedContent){ var output = '<ul>'; $(feedContent).each(function(){ output = output + '<li>' + this.title + '</li>'; }); output = output + '</ul>'; $('.content').html(output); } /* สร้างฟังก์ชันสำหรับอ่าน feed จาก url */ var parseFeed = function(url){ $.ajax({ url: document.location.protocol + '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=10&callback=?&q=' + encodeURIComponent(url), dataType: 'json', success: function(data) { var feedContent = data.responseData.feed.entries; /* รันฟังก์ชันแสดง content จาก feed โดยใช้ข้อมูลที่อ่านมาได้ */ showFeed(feedContent); /* บันทึกข้อมูลจาก feed ลงใน localStorage */ localStorage.setItem('feedContent', JSON.stringify(feedContent)); } }); } /* ตรวจสอบว่ามีข้อมูลเก็บไว้ใน localStorage แล้วหรือยัง? */ if(localStorage.getItem('feedContent') != null){ /* ถ้ามีแล้ว ให้รันฟังก์ชันแสดง content จาก feed โดยใช้ข้อมูลจาก localStorage */ showFeed(JSON.parse(localStorage.getItem('feedContent'))); }else{ /* ถ้ายังไม่มี ให้อ่าน feed จาก url */ parseFeed('http://www.siamhtml.com/feed/'); } }); |
ข้อเสียของ Web Storage
อย่างไรก็ตาม web storage ก็ยังมีข้อเสียอยู่บ้าง ดังนี้
- ไม่มีการกำหนดอายุในบางกรณี เราอาจต้องการกำหนดอายุของข้อมูลที่จะจัดเก็บเหมือนกับที่ cookie ทำได้
- ไม่ปลอดภัยข้อมูลที่ถูกจัดเก็บด้วย web storage จะอยู่ในรูป string ที่อ่านรู้เรื่อง และยังสามารถดูได้ผ่านทาง web browsers อีกด้วย
ความปลอดภัยของข้อมูล
การใช้ web storage ในการเก็บข้อมูลที่เป็นความลับ มีข้อควรระวังดังนี้
- ใครๆ ก็สามารดูข้อมูลใน web storage ที่เก็บอยู่บนเครื่องนั้นๆ ได้อย่างง่ายดาย เพียงแค่พิมพ์ localStorage หรือ sessionStorage ไปที่ console ของ firebug
- ถึงแม้ว่า web storage จะถูกจำกัดการใช้งานไว้เพียงแค่ domain ที่ได้สร้างข้อมูลขึ้นมาเท่านั้น แต่หาก domain นั้นถูกโจมตีด้วย XSS แล้วล่ะก็ ข้อมูลเหล่านั้นก็จะสามารถถูกเข้าถึงโดยผู้ที่โจมตีได้อยู่ดี
- ถึงแม้ว่าเราจะเข้ารหัสข้อมูลก่อนที่จะเก็บด้วย web storage แต่มันก็จะทำให้มีขั้นตอนในการถอดรหัสเพิ่มเข้ามา และการถอดรหัสที่ฝั่ง client ก็คงไม่ปลอดภัยเท่าฝั่ง server
ด้วยเหตุผลดังกล่าว เราจึงไม่ควรใช้ web storage ในการเก็บข้อมูลที่เป็นความลับเป็นอันขาด
พิมพ์ localStorage ที่ console ของ firebug เพื่อดูว่า Mashable ใช้ localStorage เก็บข้อมูลอะไรเอาไว้บ้าง
Browsers Compatibility
เราสามารถใช้ web storage ได้แล้ววันนี้ เนื่องจาก web browsers หลักๆ รองรับแล้วทั้งหมด แม้แต่ Internet Explorer ก็ยังรองรับแล้วตั้งแต่เวอร์ชัน 8
Cookie vs. Web Storage
หากเราพิจารณาดูดีๆ จะเห็นว่า web storage นั้น ไม่ได้มาแทน cookie เลยซะทีเดียว เพราะในบางกรณี การใช้ cookie ก็ดูจะเหมาะสมกว่า ในการตัดสินใจว่าเราควรจะเลือกใช้ web storage หรือ cookie ดีนั้น ให้เราถามตัวเองว่าเราจะเก็บข้อมูลเพื่อให้ใครเอาไปใช้ ? หากเป็นฝั่ง server ให้เราใช้ cookie แต่หากเป็นฝั่ง client ก็ให้เราใช้ web storage แทน