iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 19
0
Modern Web

從0.5開始的JavaScript系列 第 19

Day19 要來塊餅乾嗎? Cookie & Session

  • 分享至 

  • xImage
  •  

不知不覺這篇寫完就剩下10天了,雖然每次都會在螢幕前面發呆,想著等等要寫的內容/images/emoticon/emoticon28.gif

今天要來聊聊 cookiesession

還記得以前要註冊會員還是玩網頁遊戲的時候,下方都會出現:「如果出現錯誤請先清除 cookie 後再試」,然後就很直觀的把 cookie 聯想成餅乾,也不知道它是幹嘛的XD

本文開始


cookie & session

cookie

在開發網頁時,要有一個很重要的觀念,那就是 HTTP 協定是無狀態的

這是什麼意思?

「簡單來說就是伺服器處理完你的 request 之後就與你無關了,而且它也不會記得你和它之間的故事,你們的關係形同陌生人,殘忍的是你又看著它與其他人展開新的故事,寫 code 再苦,也比不上它在你心中留下的傷痛,恨自己到底為什麼,直到現在還守著這份回憶,好似期待有一天還能夠回到當初,好想再看到那個屬於自己的微笑,只要一次就好,我真的...真的好想妳。」

打著打著眼淚沒有流出來,只是口有點渴而已。

蛤? 你說你正要按下檢舉?

等等,拜託不要檢舉我涉嫌文章灌水混字數,我馬上進入重點...

好啦,我們把故事改成這樣好不好,

「下班好累,開個臉蘇看廢文,聽說最近上面的年輕人越來越少了,咦!怎麼要我打帳密登入,我不是昨天才登入過,我的密碼抄在小紙上面,那張紙不知道跑去哪裡了,而且不對吧,這個使用者體驗是怎麼回事,每天打帳密就飽了!」

這個就是 HTTP 無狀態 特性,伺服器並不會知道你之前做了什麼,常見的例子還有購物車,買了好幾個商品要結帳,結果伺服器不知道我到底買了什麼。

cookie 可以用來解決這個問題,它能夠儲存一些資訊,像是我拿著會員卡,就能夠直接進入商店,因為上面的卡號說明了我是這家店已經付費過的客人,也就是他們的會員,所以我不用再付費就能夠入場。

特性

以下是 cookie 的特性,

  1. 可以紀錄使用者訊息。
  2. 儲存在客戶端。
  3. 連線時會自動帶上,但過多的 cookie 可能會浪費流量、或是帶上無用之 cookie
  4. 大小限制 4kb 左右。
  5. 能夠設置過期時間。
  6. 專屬於某網域(路徑),也就是 google.com 的頁面不能存取 facebook.com 的 cookie

session

那什麼是 session 呢?

比較不嚴謹的解釋是,可以把 session 當成 server 版的 cookie,那什麼時候又會用到呢?

舉回我們剛剛的例子,如果我們把辨識用戶登入的 cookie 這樣寫,

username=Bob;isLogin=true;

看起來沒問題啊,我後端收到這個 cookie,我知道他是誰,而且已經登入過,cookie 也還沒過期,所以就不用讓他打帳密,直接進入使用者畫面。

但是請記得 cookie 是儲存在用戶端的,而且是明文,所以我把 cookie 直接改成

username=Alice;isLogin=true;

那我不就可以登入查看 Alice 的資料了嗎...?

所以才需要搭配使用 session

流程大概是這樣:
=> 使用者登入
=> 後端驗證後建立 session,紀錄該用戶已登入
=> 接著回傳寫著這個 session 的 ID 的 cookie
=> 日後進入網站時,後端收到帶著 session IDcookie,然後查找這個 session 的資訊,發現已經登入
=> 讓使用者不用輸入帳密就登入網站

也有可能是不帶 session ID 的方法:
=> 使用者登入
=> 後端驗證後,設置一個寫著加密字串的 cookie
=> 日後進入網站時,後端解密這個字串,辨別用戶身分與維持登入狀態

但不管是哪種作法,原理都是把用戶 cookie 帶上的「東西」拿來查詢驗證。

「就像是我從事一個秘密交易,我透過轉帳付款,然後賣家給我一串亂碼,我只需要拿著這串亂碼,就能夠到指定地點取貨,而交貨者只需要把這段亂碼輸入他們的系統查詢,就能夠驗證我的個人資訊以及是否付款,而且我也不知道這串亂碼的規則,所以不能自己編造一個亂碼去取貨。」

JS with cookie

講了那麼多,我們來看看怎麼使用 JS 操作 cookie

查看 cookie

document.cookie;
// EX: username=Bob; age=18;

操作 cookie

cookie 說穿了就是 key=value 的形式而已,但是我們剛剛透過 document.cookie 查看時,發現它們全部被組成字串,如果我只是要單純存取某個屬性的值而已,不就還要自己切割字串嗎?

沒錯! 還真的要自己切割字串, JS 本身沒有提供這些方法,所幸 W3C 有附上常用操作的函數,那就讓我們來看看吧。

取得指定屬性的值

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i <ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

EX: 我想要取得 username,就可以這樣寫,找到就會回傳,沒找到就回傳 ""

var myName = getCookie("username"); // Bob

設置 cookie

function setCookie(cname, cvalue, exdays) {
    var d = new Date();
    d.setTime(d.getTime() + (exdays*24*60*60*1000));
    var expires = "expires="+ d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

EX: 我想設置紀錄身高cookie

setCookie("height", 180);

補充

其實有更方便的工具來操作/查看 cookie,像是瀏覽器內建的開發者工具,

  1. 以 chrome 為例:

可以一目瞭然所有的 NameValueDomainPathExpiresHTTP

  1. 或是使用方便的插件(chrome extension)

安全性

這邊有注意到嗎,上面有一個 HTTP OnlySecure,它們分別代表的意思是

  • HTTP Only: 設定的話 cookie 只能被 server 端存取,無法在用戶端存取,也就是設定的話沒辦法透過 JS 去操作它。
  • Secure: cookie 只允許在 HTTPS 下傳輸。

那今日的分享就到這,我們明天見/images/emoticon/emoticon51.gif


上一篇
Day18 來點 BOM 吧!
下一篇
Day20 localStorage、sessionStorage
系列文
從0.5開始的JavaScript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言