我們來聊聊Cookie、Session和Storage的那些事

Z不懂發表於2019-02-16

導語

我們在做專案的時候,經常把Cookie和Session掛在嘴邊,可實際對於他們瞭解的也是很少,只是會使用,但這遠遠不夠,熟練的掌握他們的特性才能把專案做的更好。下面我們就來認識一下他們吧!

### 先來了解一下Cache

Cache表示資料快取,合理的設定cache,它可以幫助我們提高訪問速度,減少請求(在快取有效期內直接讀取Cache檔案),減少檔案從伺服器直接拉取檔案(快取過期後,請求伺服器器檢查檔案是否被更改,如沒有被更改則返回304然後讀取Cache);

Cache的資料一般是伺服器上不經常變動的資料,如圖片、某些資料js、html、php等;如果是經常變動的資料一般是不被快取的,沒有意義;如果把一個經常變動的檔案快取起來的話,沒有多大意義。

讀取Cache的過程

首先檢查檔案設定的快取是否過期:

  • 如果過期了,則會重新傳送請求到伺服器,檢查該檔案是否有被更新,如果沒有被更新,則伺服器會返回304 Not Modified,表示伺服器上該檔案沒有被更新,使用者發起的對該檔案請求則會直接從本地cache讀取;如果服務上檔案被更新了,則伺服器會返回新的檔案,此時http返回碼為200 ok,更新快取。
  • 如果沒有過期,則會直接讀取本地cache檔案,不再發起http請求;

在瀏覽器的控制檯的Network,我們可以看到一些檔案的Headers,我們來說說其中的一些頭部設定的作用:

Responese Headers

access-control-allow-origin:*
cache-control:max-age=691200
content-length:0
date:Sun, 22 Apr 2018 03:25:41 GMT
etag:"5ad8603c-214cb"
expires:Fri, 27 Apr 2018 13:33:04 GMT
server:marco/2.0
status:304
via:T.3.H, M.ctn-fj-foc-007
x-request-id:30e1ceac71122f15ed9144c272406682

Request Headers

:authority:static.segmentfault.com
:method:GET
:path:/v-5ad86038/3rd/assets.js
:scheme:https
accept:*/*
accept-encoding:gzip, deflate, sdch, br
accept-language:zh-CN,zh;q=0.8
cache-control:max-age=0
if-modified-since:Thu, 19 Apr 2018 09:24:12 GMT
if-none-match:W/"5ad8603c-214cb"
origin:https://segmentfault.com
referer:https://segmentfault.com/user/settings?tab=notify
user-agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.5006.400 QQBrowser/9.7.13080.400
  • expires

    expires是HTTP/1.0控制網頁快取的欄位,表示伺服器返回該請求結果快取的到期時間,即再次發起該請求時,如果客戶端的時間小於Expires的值時,直接使用快取結果;expires=當前伺服器date+快取有效時間;時間格式為GTM,是一個絕對值。

  • cache-control

    使用者控制http的快取,max-age表示客戶端可以接收生存期不大於指定時間(以秒為單位)的響應;max-age=0;表示每次請求該檔案時,都需要請求伺服器檢查檔案在上一次被快取時有無修改過;max-age=10;表示10s內再次對該檔案發起請求則不需要向伺服器發起請求讀取檔案,直接讀取本地cache檔案;

    在HTTP/1.1中,Cache-Control是最重要的規則,主要用於控制網頁快取,主要取值為:

    • public:所有內容都將被快取(客戶端和代理伺服器都可快取)
    • private:所有內容只有客戶端可以快取,Cache-Control的預設取值
    • no-cache:客戶端快取內容,但是是否使用快取則需要經過協商快取來驗證決定
    • no-store:所有內容都不會被快取,即不使用強制快取,也不使用協商快取
    • max-age=xxx (xxx is numeric):快取內容將在xxx秒後失效,是一個相對值
由於**Cache-Control的優先順序比expires**,那麼直接根據Cache-Control的值進行快取,意思就是說在600秒內再次發起該請求,則會直接使用快取結果,強制快取生效。

***注:在無法確定客戶端的時間是否與服務端的時間同步的情況下,Cache-Control相比於expires是更好的選擇,所以同時存在時,只有Cache-Control生效。***

以上只是簡單的瞭解一下Cache,更深入的瞭解瀏覽器的快取機制,可以看看這篇文章–>徹底理解瀏覽器的快取機制,講得深入,看完會對你有很大的幫助。

Cookie

Cookie是客戶端儲存資料的一個一種選項

當我們向伺服器傳送任意的HTTP請求的時候,伺服器會返回一個帶有Set-Cookie的HTTP響應頭返回給瀏覽器,其中包含一些會話資訊。這種響應頭可能如下:

// Response Headers 響應頭

HTTP/1.1 200 OK
Server: nginx/1.10.1
Date: Sun, 22 Apr 2018 06:16:14 GMT
Content-Type: text/html
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: SID=t65ln3kllu7ujutldk4hcota05; path=/
Content-Encoding: gzip

這個響應頭設定SID為名稱,t65ln3kllu7ujutldk4hcota05為值的一個Cookie。

如果使用者不是第一次訪問,即:本地已經存在cookie,則在傳送請求時會將cookie一併發給伺服器,伺服器收到請求之後會作出相應處理,返回對應的資訊;這種請求頭可能如下:

// request Headers 請求頭

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Connection:keep-alive
Cookie: SID=t65ln3kllu7ujutldk4hcota05

Cookie的設定

設定方式為:

document.cookie="name=value;domain=域名;path=/;expires=過期時間;secure"

其中name和value是必須,其他為可選;name和value都需要經過URL編碼–encodeURIComponent()

現在介紹一下Cookie的構成:

  • name :一個唯一確定Cookie的名稱,不區分大小寫,獲取Cookie是根據name來查詢
  • value:儲存在Cookie中的字串值
  • domain:Cookie對於哪個域有效,比如domain=”aa.qq.com”,那麼qq.com就不可以讀取該Cookie,如果沒有設定,會預設該請求來自當前域。
  • path:對於指定域中的哪個路徑。比如path=”/book/”,那麼對於www.aa.qq.com/cc/的請求就不能傳送Cookie
  • expires:Cookie過期時間,這個值是GMT格式的日期
  • secure:設定這個標誌後,Cookie只有在SSL連結的時候才會傳送給伺服器,比如https://www.aa.qq.com可以,而http://www.aa.qq.com就不行

Cookie的缺點

  • Cookie在每個瀏覽器以及版本的數量都不同

    • IE6一下版本每個域名最多20個
    • IE7以上的版本每個域名最多50個
    • FireFox每個域名最多50個
    • Opera每個域名最多30個
    • Safari和Chrome沒有硬性規定,應該是有一個極限的
  • 大小受限,一般是在4k左右,最好別超過4k
  • 使用者可以操作禁用cookie,使功能受限
  • 安全性較低
  • 有些狀態不可能儲存在客戶端
  • 每次訪問都要傳送cookie給伺服器,浪費頻寬。
  • cookie資料有路徑(path)的概念,可以限制cookie只屬於某個路徑下。

瀏覽器提供設定Cookie方法比較簡陋,操作會比較麻煩,我們可以自己動手封裝一個

class CookieUtil{
    constructor(){

    }

    get(name){
        var cookies=document.cookie.split(";");
        var curCookie;
        for(var i=0;i<cookies.length;i++){
            curCookie=cookies[i].split("=");
            if(decodeURIComponent(curCookie[0])===name){
                return decodeURIComponent(curCookie[1])
            }

        }
        return null;
    }
    set(name,value,expires,domain,path,secure){
        if(!name&&!value){
            return
        }
        var cookieStr=encodeURIComponent(name)+"="+encodeURIComponent(value);
        if(expires && (expires instanceof Date)){
            cookieStr+=";expires="+expires.toGMTString();
        }

        if(path){
            cookieStr+=";path="+path
        }
        if(domain){
            cookieStr+=";domain="+domain
        }
        if(secure){
            cookieStr+=";secure"
        }
        document.cookie=cookieStr;
    }

    delete(name,domain,path,secure){
        this.set(name,"",new Date(0),domain,path,secure)
    }
}

Session

Session是儲存在服務端的,通過類似與Hashtable的資料結構來儲存,能支援任何型別的物件(session中可含有多個物件)

Session機制

當伺服器收到請求需要建立session物件時,首先會檢查客戶端請求中是否包含sessionid。如果有sessionid,伺服器將根據該id返回對應session物件。如果客戶端請求中沒有sessionid,伺服器會建立新的session物件,並把sessionid在本次響應中返回給客戶端。通常使用cookie方式儲存sessionid到客戶端,在互動中瀏覽器按照規則將sessionid傳送給伺服器。如果使用者禁用cookie,則要使用URL重寫,可以通過response.encodeURL(url)進行實現;API對encodeURL的約束為:當瀏覽器支援Cookie時,url不做任何處理;當瀏覽器不支援Cookie的時候,將會重寫URL將SessionID拼接到訪問地址後。

Session的優點

  • 大小沒有限制
  • session的安全性大於cookie,原因如下:

    • sessionID儲存在cookie中,若要攻破session首先要攻破cookie
    • sessionID是要有人登入,或者啟動session_start(php中的方法)才會有,所以攻破cookie也不一定能得到sessionID
    • 第二次啟動session_start後,前一次的sessionID就是失效了,session過期後,sessionID也隨之失效。
    • sessionID是加密的

Session的缺點

  • Session儲存的東西越多,就越佔用伺服器記憶體,對於使用者線上人數較多的網站,伺服器的記憶體壓力會比較大。
  • 依賴於cookie(sessionID儲存在cookie),如果禁用cookie,則要使用URL重寫,不安全
  • 建立Session變數有很大的隨意性,可隨時呼叫,不需要開發者做精確地處理,所以,過度使用session變數將會導致程式碼不可讀而且不好維護。

Storage

WebStorage目的是克服由cookie所帶來的一些限制,當資料需要被嚴格控制在客戶端時,不需要持續的將資料發回伺服器。

Webstorage的兩個主要目標:

  • 提供一種在cookie之外儲存會話資料的路徑。
  • 提供一種儲存大量可以跨會話存在的資料的機制。

HTML5的WebStorage提供了兩種API:localStorage(本地儲存)和sessionStorage(會話儲存)。

  • 生命週期

    • localStorage:localStorage的生命週期是永久的,關閉頁面或瀏覽器之後localStorage中的資料也不會消失。localStorage除非主動刪除資料,否則資料永遠不會消失。
    • sessionStorage的生命週期是在僅在當前會話下有效。sessionStorage引入了一個“瀏覽器視窗”的概念,sessionStorage是在同源的視窗中始終存在的資料。只要這個瀏覽器視窗沒有關閉,即使重新整理頁面或者進入同源另一個頁面,資料依然存在。但是sessionStorage在關閉了瀏覽器視窗後就會被銷燬。同時獨立的開啟同一個視窗同一個頁面,sessionStorage也是不一樣的。
  • 儲存大小:

    • localStorage和sessionStorage的儲存資料大小一般都是:5MB
  • 儲存位置:

    • localStorage和sessionStorage都儲存在客戶端,不與伺服器進行互動通訊。
  • 儲存內容型別:

    • localStorage和sessionStorage只能儲存字串型別,對於複雜的物件可以使用ECMAScript提供的JSON物件的stringify和parse來處理
  • 獲取方式:

    • localStorage:window.localStorage;;
    • sessionStorage:window.sessionStorage;。
  • 應用場景:

    • localStoragese:常用於長期登入(+判斷使用者是否已登入),適合長期儲存在本地的資料。
    • sessionStorage:敏感賬號一次性登入;

WebStorage的優點:

  • 儲存空間更大:

    • cookie為4KB,而WebStorage是5MB;
  • 節省網路流量:

    • WebStorage不會傳送到伺服器,儲存在本地的資料可以直接獲取,也不會像cookie一樣美詞請求都會傳送到伺服器,所以減少了客戶端和伺服器端的互動,節省了網路流量;
  • 對於那種只需要在使用者瀏覽一組頁面期間儲存而關閉瀏覽器後就可以丟棄的資料,sessionStorage會非常方便;
  • 快速顯示:

    • 有的資料儲存在WebStorage上,再加上瀏覽器本身的快取。獲取資料時可以從本地獲取會比從伺服器端獲取快得多,所以速度更快;
  • 安全性:

    • WebStorage不會隨著HTTP Header傳送到伺服器端,所以安全性相對於cookie來說比較高一些,不會擔心截獲,但是仍然存在偽造問題;
  • WebStorage提供了一些方法,資料操作比cookie方便;

    • setItem (key, value) —— 儲存資料,以鍵值對的方式儲存資訊。
    • getItem (key) —— 獲取資料,將鍵值傳入,即可獲取到對應的value值。
    • removeItem (key) —— 刪除單個資料,根據鍵值移除對應的資訊。
    • clear () —— 刪除所有的資料
    • key (index) —— 獲取某個索引的key

相關文章