Local & Session Storage

Bugün sizlere HTML5 ile hayatımıza giren 2 özellik hakkında kısaca konuşmak istiyorum, bunlar konunun başlığındanda anlaşılacağı gibi Local Storage ve Session Storage özellikleri.

Fakat ben uygulamalara özel detaylara hiç dallanmadan bu makalede basit kullanım yönergelerini, nerede kullanılabileceğini, güvenlik hakkında düşünmemiz gerekenleri, limitasyonlarını ve bu limitasyonları nasıl aşacağımız hakkında bilgileri sizlere aktarmaya çalışacağım.

Öncelikle Local ve Session Storage nedir konusundan başlayalım. Local Storage ve Session Storage bir keskin fark dışında tamamen aynı amaca hizmet ederler, istemci tarafında veri barındırma (client side storage).

Peki bunlar aynı işi yapıyorsa o zaman neden HTML5 spesifikasyonu tarafından Local ve Session Storage olarak 2 farklı parçaya bölündüler.

Aslında localStorage ve sessionStorage objeleri aynı objeden (Storage) türemişlerdir. Aralarında sessionStorage objesinin non-persistence yaklaşımı dışında hiç bir fark bulunmamaktadır.

localStorage tarafında barındırılan veri, girip elle silinmediği veya silinmesine sebep olabilecek bir işlem olmadığı sürece olduğu yerde kalacaktır, bir kere kaydedildikten sonra kaydedildiği andan itibaren daha sonra siteye yapılacak herhangi bir ziyarette veriler varlığını sürdüreceklerdir.

sessionStorage tarafında kaydedilen veri sadece kaydedildiği pencerede geçerlidir (veya Chrome, Firefox gibi browserlarda tablerde). bir kere kaydedildikten sonra bulunan pencere kapatılmadığı sürece veriler varlığını sürdüreceklerdir. Pencere kapatıldığında sessionStorage boşaltılacaktır. Reload veya Restore durumlarında herhangi bir veri kaybı yaşanmayacaktır. Yinede bu özellikler tarayıcı implementasyonu tabanlı olarak küçük farklılıklar gösterebilir.

Storage üstünde barındırdığınız değerler key-value pair olarak bulunmaktadır. Backend üstüne çalışan arkadaşlar bunu Memcached yada Redis ( Sadece basit SET-GET işlemleri ) üstünde veri barındırırmış gibi düşünebilir,

message-seen-4570: false
message-seen-4571: true

Gibi veri barındırmaktadır, JavaScript Weak Typing bir scripting dili olduğu için value bölümünde istediğiniz tipten veri barındırabilirsiniz. (String, Integer, Float, Double, JSON (Ufak bir hack yardımıyla :)) vs)

Tarayıcı Desteği

Kullanım Yönergeleri

localStorage ve sessionStorage objeleri hemen window objesinin altında bulunmaktadırlar, bundan dolayı direk kendi isimleriyle global seviyede kendilerine erişebilirsiniz.

# Veri Kaydetme
localStorage.setItem('user-theme', 'dark'); // Local Storage  
sessionStorage.setItem('user-theme', 'dark'); // Session Storage  

Json yazmak için küçük bir değişiklik yapmamız lazım :)

var themeObject = { 'nav': '#00aeff', 'content': '#333', 'menu': '#999' };

localStorage.setItem('user-theme', JSON.stringify(themeObject)); // Local Storage  
sessionStorage.setItem('user-theme', JSON.stringify(themeObject)); // Session Storage  

JSON.stringify() fonksiyonu bizim objemizi alıp String biçiminde serialize ediyor.

# Veri Okuma
var theme = localStorage.getItem('user-theme'); // Local Storage  
console.log(theme); // dark

var theme = sessionStorage.setItem('user-theme', 'dark'); // Session Storage  
console.log(theme); // dark  

Json okumak için küçük bir değişiklik yapmamız lazım :)

var themeObject = JSON.parse(localStorage.getItem('user-theme')); // Local Storage  
console.log(themeObject); // JSON Dump

var themeObject = JSON.parse(sessionStorage.setItem('user-theme', 'dark')); // Session Storage  
console.log(themeObject); // JSON Dump  

Dipnot: Gerçek kullanım durumlarında mutlaka getItem fonksiyonundan null dönme durumunu elden geçirin.

# Veri Silme
localStorage.removeItem('user-theme'); // Local Storage  
sessionStorage.removeItem('user-theme'); // Session Storage  
# Tamamen Temizleme
localStorage.clear(); // Local Storage  
sessionStorage.clear(); // Session Storage  
Nerede kullanmalıyım?

Bunu kullanabileceğiniz durumu sayısı tamamen sizin hayal gücünüzle sınırlı. Ben aklıma gelenleri hemen sizlerle paylaşıyorum;

  • Kullanıcının lokalizasyon (Dil - Para birimi vs.) bilgilerini burada tutup daha sonra kullanabilirsiniz.
  • Benim örneklerden gittiğim gibi sisteme basit bir tema desteği eklenebilir.
  • AngularJS veya ReactJS kullanarak bir SPA uygulaması geliştiriyorsanız authentication kısmında OAuth gibi bir Authentication Framework'e sahipseniz token bilgilerinizi burada tutabilirsiniz, ve Api istekleri yaparken Authorization: Bearer Token şeklinde isteklerinize token ekleyebilirsiniz.
  • Sadece o kullanıcıya gösterilecek ve herhangi bir şekilde Backend'de bulunmasına gerek olmayan verileri burada tutabilirsiniz,
  • Örneğin form doldururken belli eventlerin gerçekleşmesine veya belli bir zaman intervalinde formu kaydedip herhangi bir kayıp durumunda formu tekrar populate edebilirsiniz.
  • Yada bir form-wizard üzerinde son kalan adıma kullanıcıyı taşıyabilirsiniz.
  • HTTP stateless bir protokoldür, bu protokolün üstünde bir nebze bir state kazandıran herhangi bir iş geçerli bir kullanım senaryosu haline dönüşebilir.
Güvenlik
  • Mümkün olduğunca localStorage içinde hassas bilgiler barındırılmamalıdır, herhangi bir kriptolama işleminden geçmeden depolanan veri kullanıcının bilgisayarına geçen kişi tarafından kolaylıkla okunabilecektir.
  • localStorage ne kadar persistance bir storage sağlasa da yine de burada barındırılan veri her zaman uçucu (volatile) olacaktır. Veriniz değer taşıyan bir yapıdaysa backend üzerinde herhangi bir RDBMS yada NoSQL tarafında barındırılması doğru olacaktır.
  • XSS tehlikesi yine peşimizde bu noktada yazacağınız kodların oluşturabileceği XSS açıklarını düşünmeniz gerekecektir.
Limitasyonlar
  • Peki M.Ö 540 yılından kalma tarayıcılarıyla giren arkadaşlar ne yapacak onları üzecek miyiz? Tabi ki hayır onlar için kendimiz bir fallback yapısı oluşturmamız gerekecek, yani eğer localStorage desteklenmiyorsa, bizde HTTP'nin bize getirdiği lezzetli Cookieleri kullanacağız :)

Js-Cookie: https://github.com/js-cookie/js-cookie

Aşağıdaki library'i projemize dahil ettikten sonra aşağıdaki gibi bir set ve get fonksiyonu yazarak gerektiği durumlarda Cookie gerektiği yerlerde ise modern yaklaşımları kullanabiliriz,

var FallbackStorage = {  
    localStorageSupport: false,

    testLocalStorageAvailable: function () {
        try {
            localStorage.setItem('test', 1);
            localStorage.removeItem('test');
            this.localStorageSupport = true;
        } catch (exception) {
            this.localStorageSupport = false;
        }
    },

    init: function () {
        // run test
        this.testLocalStorageAvailable();
    },

    set: function (key, value) {
        if (this.localStorageSupport) {
            localStorage.setItem(key, value);
        } else {
            Cookies.set(key, value);
        }
    },

    get: function (key) {
        if (this.localStorageSupport) {
            return localStorage.getItem(key);
        } else {
            return Cookies.get(key);
        }
    }
};

FallbackStorage.init();

FallbackStorage.set('drink', 'Vodka');  
FallbackStorage.get('drink');

console.log(FallbackStorage.get('drink')); // Vodka  
  • Önemli bir noktaya geldik, eğer Redis gibi ah ne güzel ben bunu alim Key-Value storage gibi kullanayım her session için alayım 100,000 key-value pair oluşturayım modundaysanız, Tarayıcı orada bir dur diyor ve kızıyor, Tarayıcısından tarayıcısına değişiyor olsa da bu konuda bazı limitasyonlar söz konusu, örneğin benim kullandığım Google Chrome barındırabileceğim veri miktarını yaklaşık 5mb olarak belirlemiş, diğer tarayıcılarda durum 3 aşağı 5 yukarı aynı, peki oldu da limiti aştık ne oluyor, setItem metodu bir exception fırlatıyor, siz Try-Catch blokları arasında bu exception'ı handle ederek bir çözüm yoluna gidebilirsiniz, bu bir yöntem diğer bir yöntem ise bu tarz intense veri barındırma durumunuz varsa WebSQL yada IndexedDB özelliklerine bakmakta fayda var, bu ortamlar size LocalStorage veya SessionStoragedan daha fazla miktarda veri barındırmanıza olanak sağlamaktadır. https://arty.name/localstorage.html bu adresten tarayıcınızın bu konudaki limitasyonunu öğrenebilirsiniz,

Ben ilk çözümü kullanacağım tavsiye edildiği gibi hayati önemi olmayan verilerinizi localStorage üzerinde tutmuyorsanız tüm veritabanını temizleyip daha sonra tekrar set metodunu çağırabilirsiniz (Muhtemelen limiti aşmanız çok farklı şeyler denemiyorsanız zor olacaktır :))

var FallbackStorage = {  
    localStorageSupport: false,

    testLocalStorageAvailable: function () {
        try {
            localStorage.setItem('test', 1);
            localStorage.removeItem('test');
            this.localStorageSupport = true;
        } catch (exception) {
            this.localStorageSupport = false;
        }
    },

    init: function () {
        // run test
        this.testLocalStorageAvailable();
    },

    set: function (key, value, fromRecursion) {
        if (this.localStorageSupport) {
            try {
                localStorage.setItem(key, value);
            } catch (exception) {
                if (fromRecursion) {
                    return; // Just Prevent Infinite Loop
                }

                localStorage.clear();
                this.set(key, value, true);
            }
        } else {
            Cookies.set(key, value);
        }
    },

    get: function (key) {
        if (this.localStorageSupport) {
            return localStorage.getItem(key);
        } else {
            return Cookies.get(key);
        }
    }
};

FallbackStorage.init();

FallbackStorage.set('drink', 'vodka');  
FallbackStorage.get('drink');

console.log(FallbackStorage.get('drink')); // Vodka  

fromRecursion değişkeni bizi sonsuz döngüden koruyacaktır. (Ne olur ne olmaz, veri kaydetme kısmında oluşan elbette sadece Exceed Limit sebebiyle gerçekleşmeyecektir.)

Şimdilik bu kadar, vakit ayırıp okuduğunuz için teşekkür ediyorum, Sevgilerle.

Batıkan Senemoğlu

Read more posts by this author.

İstanbul, Turkey https://batikansenemoglu.com